pythonにおける closure と自由変数
ほほう、上位の関数(maker)のローカル変数は、 下位の関数(func)から見るとグローバルに見えるのかと思ったが、 ローカル変数はどこまでいってもローカルなんじゃな。
ちょっと違う。func_code を見るとか dis モジュールを使うともう少し詳細が見える。
import dis g = 0 def a(): x = 0 def inner(): return x * 2 return inner def b(): def inner(): x = 10 return x * 2 return inner def c(): def inner(): global g return g * 2 return inner def inspect(func): sep = '-' * 60 print '=' * 60 print func.func_name.center(60) print '=' * 60 names = 'co_varnames co_cellvars co_freevars'.split() for name in names: print 'outer', name, '=', getattr(func.func_code, name) for name in names: print 'inner', name, '=', getattr(func().func_code, name) print sep print 'inner code' print sep dis.dis(func()) if __name__ == '__main__': inspect(a) inspect(b) inspect(c)
結果
============================================================ a ============================================================ outer co_varnames = ('inner',) outer co_cellvars = ('x',) outer co_freevars = () inner co_varnames = () inner co_cellvars = () inner co_freevars = ('x',) ------------------------------------------------------------ inner code ------------------------------------------------------------ 9 0 LOAD_DEREF 0 (x) 3 LOAD_CONST 1 (2) 6 BINARY_MULTIPLY 7 RETURN_VALUE ============================================================ b ============================================================ outer co_varnames = ('inner',) outer co_cellvars = () outer co_freevars = () inner co_varnames = ('x',) inner co_cellvars = () inner co_freevars = () ------------------------------------------------------------ inner code ------------------------------------------------------------ 14 0 LOAD_CONST 1 (10) 3 STORE_FAST 0 (x) 15 6 LOAD_FAST 0 (x) 9 LOAD_CONST 2 (2) 12 BINARY_MULTIPLY 13 RETURN_VALUE ============================================================ c ============================================================ outer co_varnames = ('inner',) outer co_cellvars = () outer co_freevars = () inner co_varnames = () inner co_cellvars = () inner co_freevars = () ------------------------------------------------------------ inner code ------------------------------------------------------------ 21 0 LOAD_GLOBAL 0 (g) 3 LOAD_CONST 1 (2) 6 BINARY_MULTIPLY 7 RETURN_VALUE
要するにローカル変数とは別に自由変数用の領域があるし、ロード/ストアの命令も別なのだな。