寒月記

住みにくいところをどれほどか寛容て

Qiita記事「Pythonのクロージャについて: 関数のスコープと、関数が第一級オブジェクトであることからちゃんと考える」の蛇足

Qiitaに Pythonのクロージャについて、自分なりにまとめた記事を投稿しました (※ブログに記事を移しました)
(https://www.kangetsu121.work/entry/2019/04/28/232143)。

ただでさえ記事が結構長くなったのと、この記事に書くとちょっと蛇足かな、
と思った点について、折角調べて気づいたことなのでこっちに書いときます。
Qiita記事を読んでなくてここにたどり着いた方は、ぜひそちらもご一読いただけると嬉しいです。

Qiitaとブログの住み分けに悩んでたので、ライトな補足や蛇足を載せてしまえ、と思ったのでした。

クロージャとなったオブジェクトには、__closure__ アトリビュートに環境情報が値として格納されている

そもそも Pythonのオブジェクトは、デフォルトで __closure__ というアトリビュートを持ってるみたいですね。
例えばこんなコードで確認してみます。

def createCounter():
    cnt = [0]
    print("running createCounter")
    print("createCounter locals are: " + str(locals()))

    def inner():
        cnt[0] += 1  # cnt[0] = cnt[0] + 1
        print(cnt)
        print("running inner")
        print("inner locals are: " + str(locals()))
    return inner

counter = createCounter()

こうすると、変数 counter はクロージャですね。
この counter のアトリビュートを一覧してみます。

>>> dir(counter)  # counterのアトリビュート一覧 (可読性のため改行)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__',
 '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__',
 '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
 '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__',
 '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__']

確かに、__closure__ というものがあります。
次はこいつの中身を見てみます。

>>> counter.__closure__
(<cell at 0x0000021B881AC828: list object at 0x0000021B88251308>,)

list object at 0x0000021B88251308 と出力されました。
リストオブジェクトを持っていることが記録されてるんですね。
もちろん、ここでいうリストオブジェクトは cnt を指しています。

さらにその値を確かめてみましょう。
__closure__ のインデックス 0の cell_contents に、内容が格納されているらしいです。

>>> counter.__closure__[0].cell_contents
[0]
>>> counter()
[1]
running inner
>>> counter.__closure__[0].cell_contents
[1]  # cntが更新された = counterの環境内の cntが更新された
>>>

おお、確かに cnt の値が出力されて、 cnt を更新すると同じように更新されてますね。

ちなみに、クロージャでないオブジェクトも __closure__ アトリビュートはありましたが、中身は空でした。

以上、気づいたけど記事に載せるには盛り過ぎかな、と思ったのでブログに書きました。
こうやって調べていくと楽しいですが、どんどん深みにはまってる感がありますね。
楽しいですが、時々は一次退却もしながらプログラミングを進めたいと思います。