2010-01-06 8 views
11

Ich fragte zuvor, wie die nested functions arbeiten, aber leider bekomme ich es immer noch nicht ganz. Um es besser zu verstehen, kann jemand bitte einige praktische Beispiele für verschachtelte Funktionen zeigen?Real-World-Beispiele für verschachtelte Funktionen

Vielen Dank

+1

Ist es die Tatsache, dass die innere Funktion die Werte der Variablen im umschließenden Bereich behält, die Sie nicht erhalten? – Skilldrick

Antwort

10

Ihre Frage hat mich neugierig gemacht, so dass ich sah in einigen realen Welt Code: die Python-Standardbibliothek. Ich habe 67 Beispiele für verschachtelte Funktionen gefunden. Hier sind ein paar, mit Erklärungen.

Ein sehr einfacher Grund, eine verschachtelte Funktion zu verwenden, ist einfach, dass die zu definierende Funktion nicht global sein muss, weil nur die umschließende Funktion sie verwendet. Ein typisches Beispiel aus Python quopri.py Standard-Bibliothek-Modul:

def encode(input, output, quotetabs, header = 0): 
    ... 
    def write(s, output=output, lineEnd='\n'): 
     # RFC 1521 requires that the line ending in a space or tab must have 
     # that trailing character encoded. 
     if s and s[-1:] in ' \t': 
      output.write(s[:-1] + quote(s[-1]) + lineEnd) 
     elif s == '.': 
      output.write(quote(s) + lineEnd) 
     else: 
      output.write(s + lineEnd) 

    ... # 35 more lines of code that call write in several places 

Hier gab es einige gemeinsame Code innerhalb der encode Funktion, so der Autor einfach in eine write Funktion herausgerechnet.


Eine andere übliche Anwendung für verschachtelte Funktionen ist re.sub.Hier einige Code aus dem json/encode.py Standard-Bibliothek-Modul:

def encode_basestring(s): 
    """Return a JSON representation of a Python string 

    """ 
    def replace(match): 
     return ESCAPE_DCT[match.group(0)] 
    return '"' + ESCAPE.sub(replace, s) + '"' 

Hier ESCAPE ist ein regulärer Ausdruck, und ESCAPE.sub(replace, s) findet alle Spiele von ESCAPE in s und ersetzt jede mit replace(match).


In der Tat, jede API, wie re.sub, die eine Funktion als Parameter akzeptiert kann zu Situationen führen, in denen verschachtelte Funktionen bequem sind. Zum Beispiel in turtle.py gibt es einige dumme Demo-Code, der dies tut:

def baba(xdummy, ydummy): 
     clearscreen() 
     bye() 

    ... 
    tri.write(" Click me!", font = ("Courier", 12, "bold")) 
    tri.onclick(baba, 1) 

onclick Sie erwartet ein Event-Handler-Funktion zu übergeben, so definieren wir ein und geben es in

+4

das sind gute Beispiele, aber sie könnten alle als globale Funktionen ohne Verlust der Funktionalität geschrieben werden. Verschachtelte Funktionen sind mehr als nur syntaktischer Zucker! Sie sollten einige Beispiele geben, wo sie notwendig sind – Claudiu

+0

Es ist auch erwähnenswert, dass verschachtelte Funktionen Overhead hinzufügen. Jedes Mal, wenn die äußere Funktion aufgerufen wird, erstellt Python eine brandneue Instanz der inneren Funktion. In vielen Fällen ist das egal, manchmal aber auch. –

8

Decorators ist eine sehr beliebte Anwendung für verschachtelte Funktionen. Hier ist ein Beispiel für einen Dekorator, der eine Aussage vor und nach jedem Aufruf der dekorierten Funktion ausgibt.

def entry_exit(f): 
    def new_f(*args, **kwargs): 
     print "Entering", f.__name__ 
     f(*args, **kwargs) 
     print "Exited", f.__name__ 
    return new_f 

@entry_exit 
def func1(): 
    print "inside func1()" 

@entry_exit 
def func2(): 
    print "inside func2()" 

func1() 
func2() 
print func1.__name__ 
+0

Verdammt! Sie haben mich geschlagen: P – Skilldrick

1

Python Decorators

Dies ist eigentlich ein anderes Thema zu lernen, aber wenn man sich die Sachen schauen auf ‚Funktionen wie Dekorateure Mit‘ finden Sie einige Beispiele für verschachtelte Funktionen zu sehen.

3

Verschachtelte Funktionen vermeiden, andere Teile des Programms mit anderen Funktionen und Variablen zu überdecken, die nur lokal sinnvoll sind.

Eine Funktion, die Fibonacci-Zahlen zurückkehren könnte wie folgt definiert werden:

>>> def fib(n): 
     def rec(): 
      return fib(n-1) + fib(n-2) 

     if n == 0: 
      return 0 
     elif n == 1: 
      return 1 
     else: 
      return rec() 

>>> map(fib, range(10)) 
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 

EDIT: In der Praxis Generatoren eine bessere Lösung für dieses sein würde, aber das Beispiel zeigt, wie die Vorteile von verschachtelten Funktionen zu übernehmen.

+1

Es ist wahrscheinlich erwähnenswert, dass jedes Mal, wenn fib aufgerufen wird, ein neues rec-Funktionsobjekt erstellt wird. In Codebereinigungsfällen kann dies oft unerwünscht sein. Für Dinge wie Dekorateure ist es grundsätzlich notwendig. –

2

Ich musste nur verschachtelte Funktionen beim Erstellen von Dekoratoren verwenden. Eine verschachtelte Funktion ist im Grunde eine Möglichkeit, einer Funktion ein Verhalten hinzuzufügen, ohne zu wissen, welcher Funktion Sie Verhalten hinzufügen.

from functools import wraps 
from types import InstanceType 



def printCall(func): 
    def getArgKwargStrings(*args, **kwargs): 
     argsString = "".join(["%s, " % (arg) for arg in args]) 
     kwargsString = "".join(["%s=%s, " % (key, value) for key, value in kwargs.items()]) 
     if not len(kwargs): 
     if len(argsString): 
      argsString = argsString[:-2] 
     else: 
     kwargsString = kwargsString[:-2] 
     return argsString, kwargsString 

    @wraps(func) 
    def wrapper(*args, **kwargs): 
     ret = None 
     if args and isinstance(args[0], InstanceType) and getattr(args[0], func.__name__, None): 
     instance, args = args[0], args[1:] 
     argsString, kwargsString = getArgKwargStrings(*args, **kwargs) 
     ret = func(instance, *args, **kwargs) 
     print "Called %s.%s(%s%s)" % (instance.__class__.__name__, func.__name__, argsString, kwargsString) 
     print "Returned %s" % str(ret) 
     else: 
     argsString, kwargsString = getArgKwargStrings(*args, **kwargs) 
     ret = func(*args, **kwargs) 
     print "Called %s(%s%s)" % (func.__name__, argsString, kwargsString) 
     print "Returned %s" % str(ret) 
     return ret 
    return wrapper 


def sayHello(name): 
    print "Hello, my name is %s" % (name) 

if __name__ == "__main__": 
    sayHelloAndPrintDebug = printCall(sayHello) 
    name = "Nimbuz" 
    sayHelloAndPrintDebug(name) 

ignorieren alle Hokuspokus in der „printCall“ Funktion jetzt für und konzentrieren sich nur die „sayHello“ -Funktion und unten. Was wir hier machen, ist, dass wir ausdrucken wollen, wie die "sayHello" -Funktion bei jedem Aufruf aufgerufen wurde, ohne zu wissen oder zu ändern, was die "sayHello" -Funktion tut. Also definieren wir die "sayHello" -Funktion neu, indem wir sie an "printCall" übergeben, was eine NEW-Funktion zurückgibt, die die Funktion "sayHello" ausführt UND druckt, wie die "sayHello" -Funktion aufgerufen wurde. Dies ist das Konzept der Dekorateure.

Putting "@printCall" über der sayHello Definition erfüllt das Gleiche:

@printCall 
def sayHello(name): 
    print "Hello, my name is %s" % (name) 

if __name__ == "__main__": 
    name = "Nimbuz" 
    sayHello(name) 
+0

Ich erkannte, dass die "getArgKwargStrings" auch eine verschachtelte Funktion ist. Es ist verschachtelt, weil es nur innerhalb der "printCall" -Funktion benötigt wird und nicht anderweitig aufgerufen werden muss. – manifest

+0

Wie Herr Fooz oben in einem anderen Beispiel erwähnt hat, wird die verschachtelte Funktion "getArgKwargStrings" innerhalb von "printCall" immer dann definiert, wenn die Funktion "printCall" aufgerufen wird, was wünschenswert sein kann oder auch nicht. – manifest

2

Sie sind nützlich bei der Verwendung. Funktionen, die andere Funktionen als Eingabe annehmen. Sagen Sie bitte in einer Funktion sind, und wollen eine Liste der Elemente auf dem Artikel Wert in einem dict sortieren:

def f(items): 
    vals = {} 
    for i in items: vals[i] = random.randint(0,100) 
    def key(i): return vals[i] 
    items.sort(key=key) 

Sie Schlüssel nur definieren können, genau dort und es vals verwenden haben, eine lokale Variable.

Ein anderer Anwendungsfall sind Callbacks.

1

OK, außer Dekoratoren: Angenommen, Sie hatten eine Anwendung, in der Sie eine Liste von Strings basierend auf Teilstrings sortieren mussten, die von Zeit zu Zeit variierten. Jetzt nimmt die sorted Funktionen ein key= Argument, das eine Funktion eines Arguments ist: die Elemente (Strings in diesem Fall) sortiert werden. Wie kann man dieser Funktion mitteilen, auf welche Teilstrings zugegriffen werden soll? Ein Verschluss oder eine verschachtelte Funktion, ist dafür perfekt:

def sort_key_factory(start, stop): 
    def sort_key(string): 
     return string[start: stop] 
    return sort_key 

Einfach eh? Sie können dies erweitern, indem Sie start und stop in ein Tupel oder ein Slice-Objekt einkapseln und dann eine Sequenz oder eine iterierbare davon an die sort_key_factory übergeben.

2

Noch ein anderes (sehr einfaches) Beispiel. Eine Funktion, die eine andere Funktion zurückgibt. Beachten Sie, dass die innere Funktion (die zurückgegeben wird) Variablen aus dem Bereich der äußeren Funktion verwenden kann.

def create_adder(x): 
    def _adder(y): 
     return x + y 
    return _adder 

add2 = create_adder(2) 
add100 = create_adder(100) 

>>> add2(50) 
52 
>>> add100(50) 
150 
Verwandte Themen