2017-11-25 26 views
0

まず最初に、私はデコレータが何であるか知っています。私はいくつかの小さな側面を理解したいと思います。 、今実際にPythonデコレータはどのように定義されていますか?

@viking_chorus 
def menu_item(): 
    print("spam") 

def menu_item(): 
    print("spam") 
menu_item = viking_chorus(menu_item) 

のは、このwebsiteに説明を見てみましょう:;

TL DR

is decorator func1 = func2(func1) # True 
is decorator func3 = func2(func1) # ??? 

はの機能を飾るために2つの同等の方法を説明しWikiを見てみましょう特にセクションのデコレータに戻る。そこ定義された2つの関数です:

def make_pretty(func): 
    def inner(): 
     print("I got decorated") 
     func() 
    return inner 

def ordinary(): 
    print("I am ordinary") 

は、そして著者は、関数を飾ると、それを呼び出す:

>>> pretty = make_pretty(ordinary) 
>>> pretty() 
I got decorated 
I am ordinary 

私たちは、著者が使用していないことに気付くことができます。

>>> ordinary = make_pretty(ordinary) 

Wikiが推奨する方法です(私はWikiが間違っていることがあることを知っています)。だから私は、このtutorialから取られたフィボナッチ数の機能を飾るために最後の方法を使用することにしました:

def memoize(f): 
    memo = {} 
    def helper(x): 
     if x not in memo:    
      memo[x] = f(x) 
     return memo[x] 
    return helper 


def fib(n): 
    if n == 0: 
     return 0 
    elif n == 1: 
     return 1 
    else: 
     return fib(n-1) + fib(n-2) 

このコール:

>>> fib_element = memoize(fib) 
>>> fib_element(40) 

fib()がされていることを意味し、私のマシン上で長い時間がかかります正しく装飾されていない。実行時間はfib(40)に匹敵します。これらの呼び出し:

>>> fib = memoize(fib) 
>>> fib_element = fib # assigned after decoration 
>>> fib(40) 
>>> fib_element(40) 

実行が速い。だから問題は:ordinaryの機能をpretty = make_pretty(ordinary)に飾っていると言うことができますか?

+1

技術的には、デコレータと呼ばれる明確なオブジェクトはありません。実際には関数を引数としてとり、別の関数を返す(または返すことが期待される)関数です。何が*特別なのはデコレータ*構文*であり、これはデコレータ機能を簡潔に適用する方法を提供する。 '@foo def bar():...'は 'def bar():...よりも短いです。 bar = foo(bar) 'となります。 – chepner

答えて

2

fib_element(40)の最初の呼び出しが遅い理由は、再帰的に飾り付けを行わないということです。fib関数はメモを知りません。同じ要素に対してfib_elementを繰り返し呼び出すと、最初の呼び出しは遅くなり、他の呼び出しは非常に高速になります。

fibは、fib(2番目の例の装飾された関数を参照していますが、最初の例の元の関数)を呼び出すので、この修飾メソッドを使用してメモをとるために同じ名前を付ける必要があります。

+0

'fib'関数が最初の呼び出し中にメモを知っていない場合、なぜ同じ引数を持つ2番目と次の呼び出しが辞書を使用し、' fib_element(N) 'が速く動作するのでしょうか?これは、「フィブス」がメモを知っていることを示唆しています。 – Benek

+1

'fib'はメモされた' fib'です。 – L3viathan

+0

実際には 'fib_element = fib'は2つの名前が全く同じ関数を指し示すようにしますが、それは別個の関数ではありません。 –

関連する問題