前回までの「Python初体験」の続きです。

今回は表題の通り、ローカル(局所)変数とグローバル(大域)変数、および関数の引数のお話です。まぁ、C系言語でプログラミングを学んだ方には目新しいことはあまりないと思います。

例題で興味を持ったのが次のプログラムです。
"""\
# global_value はグローバル変数
global_value = 100

def test_global(arg):
    # ローカル変数 arg と グローバル変数 global_value の積
    return arg * global_value

print(test_global(10)) # 10 * 100\
"""

このプログラムの関数test_globalで、グローバル変数global_valueと同名のローカル変数を2で初期化して宣言するとどうなるか(命題:グローバル変数とローカル変数の何れが優先するか?)実験してみました。

"""\
# global_value はグローバル変数
global_value = 100

def test_global(arg):
    #ローカル変数argとグローバル変数global_valueの積
    return arg * global_value

def test_global2(arg):
    #ローカル変数argと同名のローカル変数global_valueの積
    global_value = 2  #このように記述するとローカル変数宣言か、グローバル変数への代入か分からないが..
    return arg * global_value

print("test_global(10)", test_global(10)) # 10 * 100
print("test_global2(10)", test_global2(10)) # 10 * 100 または 10 * 2\
print("test_global(10)", test_global(10)) # 10 * 100
"""

結果は、

test_global(10) 1000
test_global2(10) 20
test_global(10) 1000

 

となり、


(1)test_global2関数内でグローバル変数と同名のローカル変数を宣言し、2で初期化した(つもり-見た目はグローバル変数に2を代入しているようにも見える)。結果は(「グローバル変数に2を代入した場合」でも「ローカル変数を2で初期化した場合」でも変わらないが)20(10 * 2)となった。
(2)その後、再度test_globalを実行すると、値100のグローバル変数が演算に使われ、結果が1000となったので、関数内のローカル変数はグローバル変数に優先することが分かる。(また、グローバル変数と同名のローカル変数の宣言、初期化がグローバル変数として認識されない、ことが分かる。)

 

と考えられます。

 

で、待てよ?

ということで同様のプログラムをC++で作って走らせました。
#include    <stdio.h>
#include    <conio.h>    //getch()使用の為
#include    <iostream>

using namespace std;

int g_int = 100;    //グローバル変数

int calc(int n) {   //グローバル変数を使った関数
    return g_int * n;
}

int calc2(int n) {  //ローカル変数を使った関数
    int g_int = 2;  //グローバル変数と同名のローカル変数
    return g_int * n;
}

int main(int argc, char** argv) {

    cout << "calc(10)の戻り値は、" << calc(10) << "です。" << endl;
    cout << "calc2(10)の戻り値は、" << calc2(10) << "です。" << endl;
    cout << "calc(10)の戻り値は、" << calc(10) << "です。" << endl;

    getch();
}

<コンソール出力>
calc(10)の戻り値は、1000です。
calc2(10)の戻り値は、20です。
calc(10)の戻り値は、1000です。

ということでC++(Embarcadero C++:bcc32c.exe)でもローカル変数が優先されますが、C++では(型宣言が付くので「ローカル変数の宣言」と「グローバル変数の値代入」とは)構文が明確に違いますので、間違えようがありません。まぁ、グローバル変数と同名のローカル変数を使うのは避け、知らずに一緒になった場合、大きな(そして見つけにくい)バグとなる可能性があることは肝に銘じましょう。

次に関数の引数ですが、C++と同じようにデフォルトの引数を渡すことが出来る、という話です。以下がその構文例です。
先ずサンプルとなる関数として引数が3つあるfooを宣言します。

def foo(arg1, arg,2, arg3):  #関数fooに3つの引数を設ける

この場合、呼び出しには"foo(16, 0, '相対値')"の様に引数を渡す必要があります。一方、

def foo(arg1 = 32, arg,2 = 0, arg3 = "絶対値"):  #関数fooに3つの引数を設け、32、0、"絶対値"というデフォルト引数値を設定する

の様に書くと、foo関数の3つの引数にデフォルト値を設けることが出来ます。ここまではC++と同じですね。

デフォルト値のままでよければ"foo()"と書けばよいのもC++と同じですが、arg1とarg2はデフォルト値でarg3のみ「相対値」でfoo関数を呼びたい時、

【C++】
    foo(32, 0, "相対値");    //arg1とarg2も書かなければならない

【Python】
foo(arg3 = "相対値");  #arg3だけを指定して書くことが出来る

という賢い対応が出来ます。

<テストプログラム>
def foo(arg1 = 32, arg2 = 0, arg3 = "絶対値"):
    print("関数fooの引数に",arg1, "、", arg2, "、と", arg3, "が与えられました")

print("foo()の場合↓")
foo()
print("foo(arg3 = \"相対値\")の場合↓")
foo(arg3 = "相対値")

<出力>
foo()の場合↓
関数fooの引数に 32 、 0 、と 絶対値 が与えられました
foo(arg3 = "相対値")の場合↓
関数fooの引数に 32 、 0 、と 相対値 が与えられました

ということで、C++よりも使いやすくなっていますね。では、また次回。