pythonの関数ベース


定義から開始
周知のように、関数は再利用可能なプログラムセグメントであり、文に名前を付けることができ、プログラムのどこでもこの名前を使用して文ブロックを任意に複数回実行することができます.
 
pythonの関数はdefキーワードで定義され、主に関数名、関数パラメータ、関数体、関数戻り値が含まれます.
 
 
#!/usr/bin/env python

def foo():
    return 1

print foo()

以上の例の実行結果は、次のとおりです.
 
1
この例では、関数名はfooであり、foo()によって関数を呼び出し、戻り値1を印刷する
 
関数Scope
python関数が実行されると、独自のscope、すなわち役割ドメイン(または関数に独自のnamespace、すなわちネーミングスペース)が作成されます.関数を実行するときに、関数体に変数名が見つかった場合、pythonはまず関数のnamespace内で変数を探します.
 
pythonにはいくつかの内蔵関数があります.関数のnamespacesを表示します.次に、関数のlocalとglobalの役割ドメインを表示する例を示します.
 
#!/usr/bin/env python

a_string = "This is a global variable"
def foo():
    print "locals:"
    print locals()

print "globals:"
print globals() # doctest: +ELLIPSIS

foo() # 2

実行結果:
 
globals:
{'foo': , '__builtins__': , '__file__': './2.py', 'a_string': 'This is a global variable', '__name__': '__main__', '__package__': None, '__doc__': None}
locals:
{}
組み込み関数globalsはdictを返し、中にはグローバルな変数があります(注意:私たちが定義したa_stringも中にあり、a_stringは関数外で定義されています).コードの#2でfoo関数が呼び出され、中のlocals関数は関数自体のnamespaceを返します(fooには変数が定義されていないので空です)
 
変数分解規則
関数内部でglobal変数にもアクセスできます.pythonの役割ドメインルールは、次のとおりです.
1.変数が作成された場合、local役割ドメインでデフォルトで作成されるのはlocal変数です.
2.local役割ドメイン(scope)で変数にアクセスする場合は、まずlocal役割ドメインで変数を検索し、その後、すべての周辺役割ドメインで変数を検索します.
3.local役割ドメインで変数を変更する場合、デフォルトではlocal役割ドメインで変数を検索し、見つからない場合は新しい変数を作成します.変更するglobal変数を宣言しない限り.
 
次の例はfoo関数にglobal変数を印刷する例です.
 
#!/usr/bin/env python

a_string = "This is a global variable"
def foo():
    print locals()
    print a_string #1

foo()

実行結果:
 
{}
This is a global variable
foo関数では、先にlocalsを印刷しましたが、空です.そして#1でa_を印刷stringという変数.次のようなことが起こります.
1.pythonはまずlocalsの中で探します.localsは空いているので見つかりません.
2.pythonはglobalsの中で探して、a_を見つけることができますstring、そして値を取得し、印刷します.
 
もう1つの例を見てみましょう.
 
#!/usr/bin/env python

a_string = "This is a global variable"
def foo():
    a_string = "test" #1
    print locals()
    print a_string #2


def foo1():
    global a_string #4
    a_string = "Oh. global variable has been changed in foo1."  #5

foo()
print a_string #3

print "---------------------"
foo1()
print a_string#6

実行結果:
 
{'a_string': 'test'}
test
This is a global variable
---------------------
Oh. global variable has been changed in foo1.
上のコードには、次のポイントがあります.
1.1はa_をあげるstringは値を割り当てます(つまり変数の値を修正します)、先にlocalsの中でa_を探しますtring、見つからない場合はlocal変数を新しく作成します.したがってlocalsを印刷すると、結果は{'a_string':'test'}です.
 
2.2で印刷する場合は、前述の変数分解規則に従って、localsからa_を探します.tring変数は、#1で定義されているので、直接印刷します.
3.#3はどの関数にもなく、グローバルな役割ドメインにあるので、globalsを直接検索して、a_を見つけました.string、印刷.
4.4でグローバル変数が宣言されている(a_stringは以前に宣言されていたが、ここではlocal役割ドメインでグローバルa_stringが使用されていることを示す)
#5箇所修正a_string、#4にa_が宣言されているためstringはグローバルなのでa_を変更しますstring後、#6で印刷されるのは修正後の値です
 
変数生存サイクル
 
#!/usr/bin/env python

def foo():
    x = 1
foo()
print x # 1

 
実行結果:
Traceback (most recent call last):
File "./5.py", line 6, in
print x # 1
NameError: name 'x' is not defined
変数はいずれも生存周期(lifetime)があり,変数の生存周期は変数宣言時の役割ドメインと密接に関連している.その役割ドメインが破棄されると、変数も破棄されます.
 
上の例では、主に次のようなポイントがあります.
1.xはfoo関数内で定義され、fooのlocalsに存在するため、その役割ドメインはfoo関数の役割ドメインである.
すなわち、foo実行時にlocalsが作成され、xはlocalsにあり、終了後、fooのlocalsは破棄され、xは存在しなくなった.
2.#1でxを印刷し、#1はグローバル役割ドメインにあるため、globalsでxを探しても見つからないため、エラーが発生します.
 
関数パラメータとパラメータ
関数のパラメータとパラメータは関数のパラメータと実パラメータとも呼ばれます(パラメータと実パラメータの概念は検索学習に問い合わせることができます)
Pythonでは,関数実行時にそのパラメータとパラメータが実際にlocal変数となりlocalsに存在する.次の例を示します.
#!/usr/bin/env python

def foo(x):
    print locals()

foo(1)

結果:
{'x': 1}
パラメータxと実行時foo(1)の実パラメータ1がfoo実行時のlocal変数になっていることがわかる.
 
pythonには関数パラメータと実パラメータを定義する方法がたくさんあります.ここでは具体的には言いません.参照してください.
https://docs.python.org/2/tutorial/controlflow.html#more-on-defining-functions
 
次に、もう1つの例を貼ります.
#!/usr/bin/env python

def foo(x, y=0): # 1
    return x - y

print foo(3, 1) # 2

print foo(3) # 3

print foo(y=1, x=3) # 4

print foo() # 5

実行結果:
2
3
2
Traceback (most recent call last):
File "./7.py", line 12, in
print foo() # 5
TypeError: foo() takes at least 1 argument (0 given)
1にはxとyの2つのパラメータが定義、yはデフォルト値0を与える.
 
関数呼び出しでは,#2,#3,#4ともに問題なく,#5のみがエラーを報告した.つまり、
1.関数パラメータを定義するとき、あるパラメータにデフォルト値を設定していない場合は、関数を呼び出すときに、そのパラメータに値を設定する必要があります.
2.あるパラメータにデフォルト値が設定されている場合、関数を呼び出すときに、そのパラメータに値を割り当てることも無視することもできます.
 
関数の基礎は大体ここまで紹介して、ネスト関数、閉パッケージなどの知識について、私は別の博文の中で紹介します:
http://yunjianfei.iteye.com/blog/2186092