Python クロージャー
Python クロージャー
このチュートリアルでは、Python クロージャー、クロージャーの定義方法、およびそれを使用する理由について学びます。
ネストされた関数内の非ローカル変数
クロージャーとは何かを説明する前に、ネストされた関数と非ローカル変数とは何かを理解する必要があります。
別の関数内で定義された関数は、ネストされた関数と呼ばれます。ネストされた関数は、囲んでいるスコープの変数にアクセスできます。
Python では、これらの非ローカル変数はデフォルトで読み取り専用であり、変更するには (nonlocal キーワードを使用して) 非ローカルとして明示的に宣言する必要があります。
以下は、非ローカル変数にアクセスするネストされた関数の例です。
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
printer()
# We execute the function
# Output: Hello
print_msg("Hello")
出力
Hello
ネストされた printer()
が 関数は非ローカル msg にアクセスできました 囲んでいる関数の変数。
閉鎖関数の定義
上記の例で、関数 print_msg()
の最後の行が printer()
を返しました 関数を呼び出す代わりに?これは、関数が次のように定義されたことを意味します:
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
return printer # returns the nested function
# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()
出力
Hello
それは異常です。
print_msg()
関数が文字列 "Hello"
で呼び出されました 返された関数は another という名前にバインドされていました . another()
の呼び出し時 、 print_msg()
の実行はすでに終了していましたが、メッセージはまだ記憶されていました 関数。
一部のデータ ("Hello
この場合) コードに接続されることを Python ではクロージャー と呼びます .
外側のスコープ内のこの値は、変数がスコープ外になったり、関数自体が現在の名前空間から削除されたりした場合でも記憶されます。
Python シェルで次のコマンドを実行して、出力を確認してください。
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined
ここでは、元の関数が削除されても、返された関数は引き続き機能します。
閉鎖はいつですか?
上記の例からわかるように、ネストされた関数がそれを囲むスコープ内の値を参照する場合、Python にはクロージャがあります。
Python でクロージャを作成するために満たさなければならない基準は、次の点にまとめられています。
- ネストされた関数 (関数内の関数) が必要です。
- ネストされた関数は、外側の関数で定義された値を参照する必要があります。
- 囲んでいる関数は、ネストされた関数を返す必要があります。
クロージャを使用するタイミング
では、閉鎖は何に役立つのでしょうか?
クロージャーは、グローバル値の使用を避けることができ、何らかの形式のデータ隠蔽を提供します。また、問題に対するオブジェクト指向のソリューションを提供することもできます。
クラスに実装するメソッドがほとんどない場合 (ほとんどの場合 1 つのメソッド)、クロージャーは代替のより洗練されたソリューションを提供できます。しかし、属性とメソッドの数が増えると、クラスを実装したほうがよいでしょう.
これは、クラスを定義してオブジェクトを作成するよりもクロージャーの方が望ましい簡単な例です。しかし、好みはすべてあなた次第です。
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
# Output: 27
print(times3(9))
# Output: 15
print(times5(3))
# Output: 30
print(times5(times3(2)))
出力
27 15 30
Python デコレーターもクロージャーを多用します。
結論として、クロージャー関数に含まれる値を見つけることができることを指摘しておくとよいでしょう。
すべての関数オブジェクトには __closure__
があります クロージャー関数の場合、セル オブジェクトのタプルを返す属性。上記の例を参照すると、times3
がわかります。 および times5
はクロージャ関数です。
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
セル オブジェクトには、閉じた値を格納する属性 cell_contents があります。
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
Python