python function is first object
>>> def outer(): ... def inner(): ... print('hoge') ... return inner() ... >>> outer() hoge
inner()を返している点に注目。ここではouter()を呼び出すことでprint文の実行結果が返される。 innerを返す内容に変えてみる。
>>> def outer(): ... def inner(): ... print('hoge') ... return inner ... >>> outer() <function outer.<locals>.inner at 0x102931b80>
今度は、outer()を呼び出すとfunctionであることが返される。 ではこれをtestという変数に格納し、()をつけて呼び出すとどうなるか。
>>> test = outer() >>> test() hoge
print文の実行結果が返される。つまり下みたいなこともできてしまう。
>>> outer()() hoge
クロージャ(Function closure)について 関数はローカルスコープとして変数の名前空間を持っている。この名前空間は関数の処理が終わると無くなる。
>>> def hoge(x): ... print(x) ... >>> hoge(2) 2 >>> print(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined
当たり前と言えば当たり前。では以下の場合はどうなるか。
>>> def outer(x): ... y = 2 ... def inner(): ... print(x, y) ... return inner ... >>> hoge = outer(1)
最後の行ではouter(1)の処理が終わった後にreturnsrされるinner関数がhogeに代入されているので、名前空間が消えているのではないか?上記と同じエラーになるのではないか?という疑問が出てくる。 しかし、実行してみると、
>>> hoge <function outer.<locals>.inner at 0x104afdb80> >>> hoge() 1 2
ちゃんと意図した通りに実行できる。これは、PythonがFunction closure(クロージャ)という機能を持っているから。クロージャとは、グローバルスコープ以外で定義された関数(この場合inner)が、定義時の自分を囲むスコープの情報を保持する、というもの。
hogeのクロージャプロパティ(closure)を確認すると、intオブジェクトを2つ持っていることがわかる。
>>> hoge.__closure__ (<cell at 0x102927c10: int object at 0x10276e108>, <cell at 0x1029a7f40: int object at 0x10276e128>)