2017-11-25 2 views
0

Zunächst weiß ich, was ein Dekorateur ist. Ich würde gerne einige kleine Aspekte verstehen.Wie ist ein Python-Dekorator tatsächlich definiert?

TL; DR

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

die bei Wiki Schauen wir uns die zwei gleichwertige Wege beschreibt, eine Funktion dekorieren:

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

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

Jetzt wollen wir die Beschreibung zu diesem website sehen, besonders im Abschnitt Zurück zu Dekoratoren. Es gibt zwei Funktionen definiert:

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

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

Und dann schmückt ein Autor die Funktion und nennt es:

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

Wir bemerken, dass der Autor nicht nicht verwendet:

>>> ordinary = make_pretty(ordinary) 

die ist ein empfohlener Weg durch Wiki (Ich weiß, dass Wiki manchmal falsch sein kann). Also beschloss ich, die letzte Art und Weise zu verwenden, um die Fibonacci-Zahlen-Funktion von diesen tutorial genommen zu dekorieren:

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) 

Dieser Aufruf:

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

dauert eine lange Zeit auf meiner Maschine, was bedeutet, dass die fib() gewesen nicht richtig dekoriert. Die Ausführungszeit ist vergleichbar mit fib(40). Diese Anrufe:

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

schnell ausgeführt werden. Die Frage ist also: Können wir sagen, dass wir die ordinary Funktion in pretty = make_pretty(ordinary) Zuweisung schmücken?

+1

Technisch gibt es kein eindeutiges Objekt, das Decorator genannt wird; es ist wirklich nur eine Funktion, die eine Funktion als Argument nimmt und eine andere Funktion zurückgibt (oder voraussichtlich zurückgibt). Was * ist * besonders ist Dekorator * Syntax *, die eine übersichtliche Möglichkeit bietet, die Decorator-Funktion anzuwenden. '@foo def bar(): ...' ist kürzer als 'def bar(): ...; bar = foo (bar) '. – chepner

Antwort

2

Der Grund für den ersten Aufruf an fib_element(40) ist langsam ist, dass Sie nicht rekursiv dekorieren: Die fib Funktion weiß nicht über Ihre Memoisierung. Wenn Sie wiederholt auf demselben Element fib_element aufrufen, wird der erste Anruf langsam, die anderen sehr schnell.

ruft auf (was sich auf die verzierte Funktion im zweiten Beispiel bezieht, aber die ursprüngliche Funktion im ersten Beispiel), müssen Sie demselben Namen geben, um von der Memoisierung mit dieser Dekorationsmethode zu profitieren.

+0

Also, wenn die 'fib' Funktion während des ersten Aufrufs nichts über Memoization weiß, warum der zweite und der nächste Aufruf mit demselben Argument (wie du erwähnt hast) das Wörterbuch benutzen und das' fib_element (N) 'funktioniert schnell? Dies deutet darauf hin, dass "fib" über Memoization Bescheid weiß. – Benek

+1

Weil 'fib' jetzt der gemeldete' fib' ist. – L3viathan

+0

Eigentlich macht 'fib_element = fib' nur, dass die zwei Namen auf die gleiche Funktion zeigen, sie sind keine unterschiedlichen Funktionen. –

Verwandte Themen