この記事では、Pythonのクロージャとは何か、いつ存在するのか、どのように使用するのかを見ていきます。
クロージャの概念を理解するためには、ネストされた関数や自由変数などの基本的な概念を理解する必要があります。
次に、Pythonにおけるクロージャの実装、クロージャが存在するための条件、クロージャを使用することの利点について見ていきます。
Pythonのネストされた関数って何?
Pythonのネストされた関数とは、他の関数の内部で定義された関数のことです。
以下はネストされた関数の例です。
ここで、nested_function()は outer_function()のローカルスコープで定義され、関数呼び出し時に outer_functionから返されない限り、同じスコープ内でしか呼び出すことができません。
#nested function example def outer_function():
x = 10
print ( "It is outer function which encloses a nested function" )
def nested_function():
print ( "I am in nested function and I can access x from my enclosing function's scope. Printing x" )
print (x)
nested_function()
#Execution outer_function() |
結果を出力すると、以下の様になります。
出力:
It is outer function which encloses a nested function
I am in nested function and I can access x from my enclosing function's scope. Printing x
10 |
ネストされた関数は、そのスコープから変数にアクセスできることがわかる。
outer_functionが呼ばれると、nested_functionが定義され、最後に呼び出され、xの値が出力されます。
つまり、関数はパラメータとして渡されたり、他の関数から返されたり、任意の変数に代入されたりすることができます。
この記事もチェック:Pythonでの変数の定義やスコープ、削除、globalキーワードを解説していく
自由形式とは?
例えば、ある関数やブロックの中で変数を宣言すると、その関数やブロックの中でのみ使用することができます。
そうでない場合は、名前エラーが発生します。
ある変数が定義されていない関数やコードブロックの中で使われる場合、その変数を自由変数と呼びます。
上の例では、xは自由変数です。
なぜなら、関数はその関数が定義されているスコープで定義された変数にアクセスできるからです。
Pythonのクロージャとは?
Pythonのクロージャは、オブジェクト指向プログラミングにおいて、ネストした関数がその関数が定義されたスコープ内の変数を記憶し、アクセスできるようにするために使用されます。
クロージャの実装では、ネストされた関数と自由変数を使用します。
つまり、外側の関数のスコープにある変数がメモリ上になくても、入れ子の関数はその変数にアクセスすることができる。
このように、データはメモリ上に存在しないコードに添付され、ネストされた関数によって使用されるのです。
Pythonでクロージャが存在するための条件は何ですか?
上の説明から、Pythonでクロージャが存在するための条件を簡単に特定することができます。
- ネストされた関数が必要です。
- ネストされた関数は、その外側のスコープ、つまり外側の関数で定義された変数を参照する必要がある。
- クロージャが存在するための3つ目の最も重要な条件は、外側の関数がネストした関数を返す必要があることです。
Pythonにおけるクロージャの例
Pythonのクロージャの例を見てみましょう。
渡された数値に対して計算を行い、その結果を表示する関数が欲しいとします。
#closure example def generate_number():
print ( "I am in generate_number function and will return the inner_function when called" )
x = 999
y = 100
def inner_function(number):
result = (number * x) % y
print ( "I am in inner function and printing the result" )
print (result)
return inner_function
#execute print ( "Calling generate_number" )
do_something = generate_number()
print ( "Calling do_something" )
do_something( 77 )
|
結果は以下の通りです。
Calling generate_number I am in generate_number function and will return the inner_function when called
Calling do_something I am in inner function and printing the result
23 |
上記の例では
- 関数 generate_number() が定義され、2つの変数と関数 inner_function がスコープ内に定義されています。
- inner_functionは関数generate_numberのスコープ内にある変数xとyにアクセスすることができます。inner_functionは関数generate_numberのスコープ内にある変数xとyにアクセスでき、計算を行い結果を表示します。
- ここで、generate_number()関数を呼び出すと、実行が完了しinner_functionがdo_somethingという変数に返される。
- この時点でgenerate_numberの実行は終了し、そのスコープはメモリからクリアされる(Python Garbage Collectionを参照)。
- これで変数do_somethingは関数として動作し始める。
- この関数を呼び出すと、inner_functionが実行され、結果が表示される。
ここで注意すべき点は、generate_numberの実行が終了している間にinner_functionが実行されることだ。
このため、変数xとyはメモリ上に存在しませんが、inner関数は変数を使用することができます。
これは、データがメモリではなくコードにアタッチされていることを示しています。
これがクロージャの真骨頂だ。
なぜPythonでクロージャを使う必要があるのか?
Pythonのクロージャは、グローバル変数の使用を控えたい場合、つまりデータ隠蔽のために使うことができます。
クロージャの上手な使い方は、デコレータを実装したときです。
まとめ
さて、今日はここまでです。
Pythonの基本的なチュートリアルから高度なチュートリアルまで、あなたのニーズに合わせてたくさん取り上げています。
もしあなたが初心者なら、このPythonの初心者向けチュートリアルを試してみてください。