2013-04-16 11 views
26

機能内の機能 - 毎回ですか?私たちはこのコードを持ってみましょう

関数定義は実行可能ステートメントです:

def big_function(): 
    def little_function(): 
     ....... 
    ......... 

ザ・Pythonドキュメントを約def声明言います。その実行だから、質問がある

... 関数名をバインド: def little_function()は​​が呼び出されるたびに実行していますか? 質問は正確にdefの文であり、本体はlittle_function()ではありません。

答えて

30

あなたはdisモジュールでバイトコードを確認することができます:あなたは、内部関数のコードを見ることができるように

>>> import dis 
>>> def my_function(): 
...  def little_function(): 
...    print "Hello, World!" 
...  
... 
>>> dis.dis(my_function) 
    2   0 LOAD_CONST    1 (<code object little_function at 0xb74ef9f8, file "<stdin>", line 2>) 
       3 MAKE_FUNCTION   0 
       6 STORE_FAST    0 (little_function) 
       9 LOAD_CONST    0 (None) 
      12 RETURN_VALUE 

がコンパイルされていますのみmy_functionと呼び出すたびにロードされ、新しい関数オブジェクトが作成されます(この意味でdef little_functionmy_functionが呼び出されるたびに実行され、となります)。

+1

'MAKE_FUNCTION'バイトコード命令を実行する際のオーバーヘッドの大きさはどのように分かりますか?他のほとんどの言語では通常は動作が遅いメモリを割り当てる必要があるようです。 – martineau

+2

@martineauいいえ、大きなメモリ割り当てはありません。 'MAKE_FUNCTION' opはコードオブジェクトの参照コードを単純に増加させ、コピーする必要はありません。確かに新しい関数オブジェクトが作成されます。これは新しいPyFunctionObjectを割り当てますが、*すべての*演算がPythonオブジェクトを割り当てていることを考慮すると、パフォーマンスが "著しく"損なわれません(明らかに重要なことは、 ')。 – Bakuriu

+2

素晴らしい説明、ありがとう! – dondublon

9

内部関数のコードは一度だけコンパイルされるため、実行時の大きなペナルティは発生しません。

内側の関数クロージャは、外部関数が呼び出されるたびに更新されます。クロージャの詳細については、たとえばhereを参照してください。ここで

は、閉鎖を検討し、迅速なデモです:

def f(x): 
    a = [] 
    b = x + 1 
    def g(): 
     print a, b 
    return g 

In [28]: y = f(5) 

In [29]: y 
Out[29]: <function __main__.g> 

In [30]: y.func_closure 
Out[30]: 
(<cell at 0x101c95948: list object at 0x101c3a3f8>, 
<cell at 0x101c958a0: int object at 0x100311aa0>) 

In [31]: y.func_closure[1].cell_contents 
Out[31]: 6 
関連する問題