2016-07-07 4 views
0

Beispiel: Fibonaci rekursive Funktion mit Memoize Decorator. Beim Aufruf von function helper gibt es kein Argument. Wenn der Funktions-Helfer so definiert ist, dass er ein Argument x annimmt, erwarte ich, dass die Funktion mit einem Argument aufgerufen wird. Ich würde gerne verstehen, warum Syntax wie es ist?Warum gibt es kein Argument beim Zurückgeben der Funktion in einem Decorator.

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

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

print(fib(40)) 

Antwort

2

Sie rufen den Helfer mit dem Argument. Dekorateure sind syntaktischer Zucker für dieses

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


fib = memoize(fib) 

So Ihre fib Funktion nicht mehr die ursprüngliche fib -function. Es ist in der Tat die helper Schließung, denn das ist, was memoize zurückgibt - eine Schließung. Also, wenn Sie fib(40) anrufen, rufen Sie Art helper(40). Der memoize Decorator erstellt ein Funktionsobjekt, es ruft es nicht auf, sondern gibt es zurück.

0

Ich glaube, die Syntax ist so, dass es so schlank wie möglich aussieht. Sie setzen ein Decorator-Objekt nach dem @ (eine Funktion, die ein Argument und eine Funktion zurückgibt), und Python ruft es mit der Funktion auf, die Sie definieren. Diese

@memoize 
def fib(n): 
    ... 

ist genau äquivalent zu dem folgenden, die die Syntax Magie Dekorateur nicht verwenden:

def fib(n): 
    ... 

fib = memoize(fib) 

Wenn Sie Ihren Kopf ein wenig zu drehen, der Ansicht, dass @ tatsächlich verfolgt werden kann ein Funktionsaufruf - aber dieser Funktionsaufruf muss einen Dekorator zurückgeben, der wie oben funktioniert! Hier ist ein dummes Beispiel, das angibt, wie oft die dekorierte Funktion aufgerufen wird, aber Sie können den Startwert festlegen. (Es ist nur ein Beispiel: es ist nicht sehr nützlich ist, da nur eine Funktion eingerichtet werden kann, usw.)

def countcalls(start): 
    global _calls 
    _calls = start 
    def decorator(f): 
     def wrapper(x): 
      global _calls 
      _calls += 1 
      return f(x) 
     return wrapper 
    return decorator 

@countcalls(3) 
def say(s): 
    print(s) 

say("hello") 
# _calls is now 4 

Hier countcalls(4) definiert und kehrt (ohne sie zu nennen) die Funktion decorator, die die eingerichtete Funktion wickeln wird und gebe den Wrapper anstelle der Funktion zurück, die ich geschrieben habe.

Verwandte Themen