2009-10-19 25 views
63

Welchen Nutzen oder Auswirkungen könnten wir mit Python Code wie folgt erhalten:verschachtelte Funktion in Python

class some_class(parent_class): 
    def doOp(self, x, y): 
     def add(x, y): 
      return x + y 
     return add(x, y) 

Ich fand diese in einem Open-Source-Projekt, etwas Nützliches in der verschachtelten Funktion zu tun, aber tun absolut nichts außerhalb außer es anzurufen. (Der tatsächliche Code kann here gefunden werden.) Warum könnte jemand es so kodieren? Gibt es einen Nutzen oder Nebeneffekt für das Schreiben des Codes innerhalb der verschachtelten Funktion und nicht in der äußeren, normalen Funktion?

+4

liest Ist dies der eigentliche Code, den Sie gefunden, oder einfach nur ein vereinfachtes Beispiel, das Sie gebaut? – MAK

+0

Es ist ein vereinfachtes Beispiel. Der eigentliche Code kann hier gefunden werden: http://bazaar.launchpad.net/%7Eopenerp/openobject-server/trunk/annotate/head%3A/bin/report/render/rml2pdf/trml2pdf.py#L685 –

+2

Ihr Link (was auf HEAD zeigt) ist jetzt nicht korrekt. Versuchen Sie: http://bazaar.launchpad.net/~openerp/openobject-server/trunk/annotate/1861/bin/report/render/rml2pdf/trml2pdf.py#L685 –

Antwort

85

Normalerweise tun Sie es closures zu machen:

def make_adder(x): 
    def add(y): 
     return x + y 
    return add 

plus5 = make_adder(5) 
print(plus5(12)) # prints 17 

Inner-Funktionen zugreifen können von der umgebenden Gültigkeitsbereich Variablen (in diesem Fall die lokale Variable x) . Wenn Sie nicht auf Variablen aus dem umschließenden Bereich zugreifen, handelt es sich tatsächlich nur um normale Funktionen mit einem anderen Bereich.

+4

Dafür würde ich Partials bevorzugen: 'plus5 = functools.partial (operator.add, 5)'. Dekorateure wären ein besseres Beispiel für Verschlüsse. –

+3

Danke, aber wie Sie in dem von mir geposteten Snippet sehen können, ist das hier nicht der Fall: Die verschachtelte Funktion wird einfach in der äußeren Funktion aufgerufen. –

8

Ich kann keinen guten Grund für Code wie diesen darstellen.

Vielleicht gab es einen Grund für die innere Funktion in älteren Revisionen, wie andere Ops.

Zum Beispiel macht dies leicht mehr Sinn:

class some_class(parent_class): 
    def doOp(self, op, x, y): 
     def add(x, y): 
      return x + y 
     def sub(x,y): 
      return x - y 
     return locals()[op](x,y) 

some_class().doOp('add', 1,2) 

aber dann die innere Funktion sollte Klassenmethoden statt sein ("private"):

class some_class(object): 
    def _add(self, x, y): 
     return x + y 
    def doOp(self, x, y): 
     return self._add(x,y) 
+0

Ja, vielleicht hat doOp eine Zeichenkette genommen, um anzugeben, welcher Operator für die Argumente verwendet werden soll ... – Skilldrick

+4

Sie sollten Klassen in Python nicht einfach zum Organisieren von Funktionen verwenden ... – aehlke

+0

@aehlke - warum nicht? – ArtOfWarfare

6

Die Idee hinter lokalen Methoden ähnelt lokalen Variablen: verschmutzen Sie nicht den größeren Namensraum. Offensichtlich sind die Vorteile begrenzt, da die meisten Sprachen diese Funktionalität nicht direkt bereitstellen.

1

Sind Sie sicher, dass der Code genau so war? Der normale Grund dafür ist, eine partielle Funktion zu erstellen - eine Funktion mit eingebrannten Parametern. Der Aufruf der äußeren Funktion gibt eine Callable zurück, die keine Parameter benötigt, und kann daher irgendwo gespeichert und verwendet werden, wo es unmöglich ist, Parameter zu übergeben. Der von Ihnen gepostete Code wird dies jedoch nicht tun - er ruft die Funktion sofort auf und gibt das Ergebnis zurück, und nicht das Callable. Es könnte nützlich sein, den tatsächlich angezeigten Code zu posten.

+1

Ich habe einen Link zum ursprünglichen Code in einem Kommentar zu meiner Frage hinzugefügt. Wie Sie sehen können, ist meins ein vereinfachtes Beispiel, aber es ist immer noch fast das Gleiche. –

44

Abgesehen von Funktionsgeneratoren, bei denen die interne Funktionsgenerierung fast die Definition eines Funktionsgenerators ist, besteht der Grund für die Erstellung verschachtelter Funktionen in der Verbesserung der Lesbarkeit. Wenn ich eine kleine Funktion habe, die nur von der äußeren Funktion aufgerufen wird, dann füge ich die Definition in die Zeile ein, so dass man nicht herumspringen muss, um zu bestimmen, was diese Funktion macht. Ich kann die innere Methode immer außerhalb der Kapselungsmethode verschieben, wenn ich die Funktion zu einem späteren Zeitpunkt wiederverwenden muss.

Toy Beispiel:

import sys 

def Foo(): 
    def e(s): 
     sys.stderr.write('ERROR: ') 
     sys.stderr.write(s) 
     sys.stderr.write('\n') 
    e('I regret to inform you') 
    e('that a shameful thing has happened.') 
    e('Thus, I must issue this desultory message') 
    e('across numerous lines.') 
Foo() 
+2

Das einzige Problem ist, dass dies den Komponententest manchmal erschweren kann, weil Sie nicht auf die innere Funktion zugreifen können. – Challenger5

+1

Sie sehen so schön aus! – taper

21

Ein potentieller Vorteil der Verwendung innerer Methoden besteht darin, dass Sie lokale Methoden der äußeren Methode verwenden können, ohne sie als Argumente zu übergeben.

def helper(feature, resultBuffer): 
    resultBuffer.print(feature) 
    resultBuffer.printLine() 
    resultBuffer.flush() 

def save(item, resultBuffer): 

    helper(item.description, resultBuffer) 
    helper(item.size, resultBuffer) 
    helper(item.type, resultBuffer) 

kann wie folgt geschrieben werden, was wohl besser

def save(item, resultBuffer): 

    def helper(feature): 
    resultBuffer.print(feature) 
    resultBuffer.printLine() 
    resultBuffer.flush() 

    helper(item.description) 
    helper(item.size) 
    helper(item.type) 
Verwandte Themen