2016-08-27 13 views
2

私はPythonのデコレータについて学ぶためにしようとしている、と私はクロージャはこのメモ化の文脈では、たとえば、適用される正確にどのように、より詳細に理解したいとメモ化デコレータを理解しますmemoizeは、プログラムフローがその囲みスコープ内になくなっても、helperの囲みスコープのmemo値にバインドされた関数を返します。したがって、memoizeが繰り返し呼び出された場合、現在の値memoに応じてさまざまな関数のシーケンスが返されます。 fib(n)への呼び出しをmemoize(fib(n))への呼び出しに置き換える原因となる構文的な糖であることも理解しています。は閉鎖

nの呼び出された値がfib(n)xhelper(x)に有効に変換されているところです。クロージャに関するほとんどのチュートリアルでは、この点を明示的にしていないように見えるか、あいまいなことに、ある関数が他の関数を「閉じて」、魔法のように聞こえるだけであると、あいまいに言います。構文の使い方を知ることができますが、ここで何が起こっているのか、そしてコードが実行されるときにどのオブジェクトとデータが渡されているのかを正確に把握したいと考えています。

+1

_ "fib(n)のnの呼び出された値がヘルパー(x)のxにどのように効果的に変換されるか" _私はあなたがそれを後方に持っていると思います。例えば ​​'fib(5)'のように誰かが呼び出すと、実際に呼び出されるのは 'helper(5)'なので 'x'は' 5'です。 'helper'は' memo [5] = f(5) 'という(実際の)' fib 'を呼び出し、 'n'も' 5'です。これらは通常の関数呼び出しです。マジックは全く関係しません。 –

+0

私は非常に良い回答を見てきました(http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python/1594484#1594484 )、それは私の特別な困難に対処していないようです。 – MichaelMaggs

+0

@MichaelMaggs:あなたはデコレータがどのように機能しているか誤解しています。 –

答えて

3

あなたは@memoizeデコレータが何をしているのか誤解しました。 fibに電話するたびにデコレータは呼び出されません。デコレータは、機能ごとにに装飾されただけでと呼ばれます。

fib関数は、が一緒memoクロージャと、fクロージャとして入手可能な本来の機能オブジェクトと、helper()機能によって置き換えられる:これは置換をhelper関数を与える

>>> def fib(n): 
...  if n in (0,1): 
...   return n 
...  return fib(n - 1) + fib(n - 2) 
... 
>>> fib 
<function fib at 0x1023398c0> 
>>> memoize(fib) 
<function helper at 0x102339758> 

クロージャーを呼び出すたびに、helper()関数と同じようにmemoディクショナリーを使用して、現在の値xの結果をルックアップします。

あなたはこのインタプリタですべての作業を参照することができますが

>>> @memoize 
... def fib(n): 
...  if n in (0,1): 
...   return n 
...  return fib(n - 1) + fib(n - 2) 
... 
>>> fib 
<function helper at 0x10232ae60> 

注関数名!それはhelperです。これは、閉鎖を持っています

>>> fib.__closure__ 
(<cell at 0x10232d9f0: function object at 0x10232ade8>, <cell at 0x10232da98: dict object at 0x102353050>) 

関数オブジェクトと辞書、それらはそれぞれfmemo、です。 .cell_contentsでセルの内容にアクセスします。

>>> fib.__closure__[0].cell_contents 
<function fib at 0x10232ade8> 
>>> fib.__closure__[1].cell_contents 
{} 

オリジナルの装飾が施され機能と空の辞書大丈夫だこと。のは、この機能を使ってみましょう:01からxセットについて得られた値をだ

>>> fib(0) 
0 
>>> fib(1) 
1 
>>> fib.__closure__[1].cell_contents 
{0: 0, 1: 1} 

memo辞書に格納されています。次にfibにどちらかの値を指定すると、そのメモが使用されます。新x値が計算され、追加されます。

>>> fib(2) 
1 
>>> fib.__closure__[1].cell_contents 
{0: 0, 1: 1, 2: 1} 

あなたはより多くの計算にかかる時間タイミングで動作するどのようにうまく見ることができます。

>>> start = time.clock(); fib(500); print(format(time.clock() - start, '.10f')) 
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125L 
0.0008390000 
>>> start = time.clock(); fib(500); print(format(time.clock() - start, '.10f')) 
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125L 
0.0000220000 

>>> start = time.clock(); fib(500); print(format(time.clock() - start, '.10f')) 
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125L 
0.0000190000 

最初の呼び出しの後、メモを見ています

>>> len(fib.__closure__[1].cell_contents) 
501 
+0

ああ!それは非常に明確になります、ありがとう。デコレータが繰り返し呼び出されていたと私は確信していました。 – MichaelMaggs