わかっている人には当たり前のことですが、他の言語から来た人だと「んんん?」かもしれません。
こうなる
>>> def f(): ... def g(): ... pass ... return g ... >>> a = f() >>> b = f() >>> a is b False >>> id(a) 139834257176640 >>> id(b) 139834231735568
解説
わかりやすいように、disモジュール(標準)のバイトコードディスアセンブラで見てみましょうか。
>>> import dis >>> dis.dis(f) 2 0 LOAD_CONST 1 (<code object g at 0x7f2db33a4a50, file "<stdin>", line 2>) 3 LOAD_CONST 2 ('f.<locals>.g') 6 MAKE_FUNCTION 0 9 STORE_FAST 0 (g) 4 12 LOAD_FAST 0 (g) 15 RETURN_VALUE
中身については深く検討していないのですが*1、MAKE_FUNCTIONがあることはわかりますね。
これが関数呼び出しのたびに実行され、新たな関数オブジェクトが生成されている訳です。
名前空間だけ間借りしている訳ではありません。
なにか問題なのか
これのせいで微妙に遅くなる可能性はあるので、測ります。
コード内で使っているFizz Buzzのコードはこちらからお借りしました。
import timeit def fizzbuzz(n): for i in range(1, n): if i % 15 == 0: print("Fizz Buzz!") elif i % 3 == 0: print("Fizz!") elif i % 5 == 0: print("Buzz!") else: print(i) def f(): def fizzbuzz_infunc(n): for i in range(1, n): if i % 15 == 0: print("Fizz Buzz!") elif i % 3 == 0: print("Fizz!") elif i % 5 == 0: print("Buzz!") else: print(i) return fizzbuzz_infunc def g(): return fizzbuzz print(timeit.timeit(f, number=10**6)) print(timeit.timeit(g, number=10**6)) """ 結果=> 0.13979517295956612 0.08669622003799304 """
まあ微妙に遅いけど、気にするほどではないかも。
これを利用するとクロージャが作れるというのは有名な話ですね。
*1:そもそも私はpythonのバイトコードなんか読めない