Ich weiß, dass Standardargumente zum Zeitpunkt der Funktionsinitialisierung und nicht bei jedem Funktionsaufruf erstellt werden. Siehe folgenden Code:
def ook (item, lst=[]):
lst.append(item)
print 'ook', lst
def eek (item, lst=None):
if lst is None: lst = []
lst.append(item)
print 'eek', lst
max = 3
for x in xrange(max):
ook(x)
for x in xrange(max):
eek(x)
Was ich nicht verstehe ist, warum dies so umgesetzt wurde. Welche Vorteile bietet dieses Verhalten gegenüber einer Initialisierung zu jeder Anrufzeit?
Antworten:
Ich denke, der Grund dafür ist die einfache Implementierung. Lassen Sie mich näher darauf eingehen.
Der Standardwert der Funktion ist ein Ausdruck, den Sie auswerten müssen. In Ihrem Fall handelt es sich um einen einfachen Ausdruck, der nicht vom Abschluss abhängt, sondern freie Variablen enthalten kann
def ook(item, lst = something.defaultList())
. Wenn Sie Python entwerfen möchten, haben Sie die Wahl: Bewerten Sie es einmal, wenn die Funktion definiert wird, oder jedes Mal, wenn die Funktion aufgerufen wird. Python wählt das erste aus (im Gegensatz zu Ruby, das zur zweiten Option gehört).Hierfür gibt es einige Vorteile.
Erstens erhalten Sie eine gewisse Geschwindigkeits- und Gedächtnissteigerung. In den meisten Fällen haben Sie unveränderliche Standardargumente, und Python kann sie nur einmal anstatt bei jedem Funktionsaufruf erstellen. Dies spart (etwas) Speicher und Zeit. Natürlich funktioniert es nicht sehr gut mit veränderlichen Werten, aber Sie wissen, wie Sie umgehen können.
Ein weiterer Vorteil ist die Einfachheit. Es ist recht einfach zu verstehen, wie der Ausdruck ausgewertet wird. Bei der Definition der Funktion wird der lexikalische Gültigkeitsbereich verwendet. Andernfalls kann sich der lexikalische Bereich zwischen der Definition und dem Aufruf ändern und das Debuggen etwas erschweren. Python ist in diesen Fällen sehr unkompliziert.
quelle
Eine Möglichkeit , es zu setzen ist , dass das
lst.append(item)
nicht der Fall ist , die mutiertlst
Parameter.lst
verweist immer noch auf die gleiche Liste. Es ist nur so, dass der Inhalt dieser Liste mutiert wurde.Grundsätzlich hat Python überhaupt keine konstanten oder unveränderlichen Variablen, aber einige konstante, unveränderliche Typen. Sie können einen ganzzahligen Wert nicht ändern, sondern nur ersetzen. Sie können den Inhalt einer Liste jedoch ändern, ohne sie zu ersetzen.
Wie bei einer Ganzzahl können Sie eine Referenz nicht ändern, sondern nur ersetzen. Sie können jedoch den Inhalt des Objekts ändern, auf das verwiesen wird.
Was die einmalige Erstellung des Standardobjekts angeht, so ist dies meiner Meinung nach hauptsächlich eine Optimierung, um die Kosten für die Objekterstellung und die Garbage Collection zu senken.
quelle
Hier können Sie das gewünschte Verhalten auswählen, wie Sie in Ihrem Beispiel gezeigt haben. Wenn Sie also möchten, dass das Standardargument unveränderlich ist, verwenden Sie einen unveränderlichen Wert wie
None
oder1
. Wenn Sie das Standardargument änderbar machen möchten, verwenden Sie etwas änderbares, z[]
. Es ist nur Flexibilität, wenn auch zugegebenermaßen, es kann beißen, wenn Sie es nicht wissen.quelle
Ich denke, die eigentliche Antwort lautet: Python wurde als prozedurale Sprache geschrieben und erst nachträglich in funktionale Aspekte übernommen. Was Sie suchen, ist, dass die Standardeinstellung von Parametern als Abschluss ausgeführt wird, und dass Abschlüsse in Python wirklich nur halbherzig sind. Zum Beweis dieses Versuchs:
Das gibt,
[2, 2, 2]
wo Sie eine echte Schließung erwarten würden, um zu produzieren[0, 1, 2]
.Es gibt eine Menge Dinge, die ich gerne hätte, wenn Python die Möglichkeit hätte, Parameter, die standardmäßig in Closures enthalten sind, zu verpacken. Beispielsweise:
Wäre sehr praktisch, aber "a" ist zur Zeit der Funktionsdefinition nicht im Gültigkeitsbereich, daher können Sie dies nicht tun und müssen stattdessen Folgendes tun:
Welches ist fast das gleiche ... fast.
quelle
Ein großer Vorteil ist das Auswendiglernen. Dies ist ein Standardbeispiel:
und zum Vergleich:
Zeitmessungen in Ipython:
quelle
Dies liegt daran, dass die Kompilierung in Python durch Ausführen des beschreibenden Codes ausgeführt wird.
Wenn einer sagte
es wäre ziemlich klar, dass Sie jedes Mal ein neues Array wollten.
Aber was ist, wenn ich sage:
Hier würde ich vermuten, dass ich Dinge in verschiedenen Listen erstellen und einen einzigen globalen Sammelbegriff haben möchte, wenn ich keine Liste spezifiziere.
Aber wie würde der Compiler das erraten? Warum also versuchen? Wir könnten uns darauf verlassen, ob dies benannt wurde oder nicht, und es könnte manchmal helfen, aber in Wirklichkeit würde es nur raten. Gleichzeitig gibt es einen guten Grund, es nicht zu versuchen - Konsistenz.
So wie es ist, führt Python nur den Code aus. Der Variablen list_of_all ist bereits ein Objekt zugewiesen, sodass dieses Objekt als Referenz in den Code übergeben wird, der standardmäßig x enthält, so wie ein Aufruf einer Funktion eine Referenz auf ein lokales Objekt erhalten würde, das hier genannt wird.
Wenn wir den unbenannten vom benannten Fall unterscheiden wollten, würde dies bedeuten, dass der Code bei der Kompilierung die Zuweisung auf eine wesentlich andere Weise ausführt als zur Laufzeit. Also machen wir den Sonderfall nicht.
quelle
Dies geschieht, weil Funktionen in Python erstklassige Objekte sind :
Es wird weiter erläutert, dass durch das Bearbeiten des Parameterwerts der Standardwert für nachfolgende Aufrufe geändert wird und dass eine einfache Lösung mit der Verwendung von None als Standard mit einem expliziten Test im Funktionskörper alles ist, was erforderlich ist, um keine Überraschungen zu gewährleisten.
Dies bedeutet,
def foo(l=[])
dass diese Funktion beim Aufruf eine Instanz dieser Funktion wird und für weitere Aufrufe wiederverwendet wird. Stellen Sie sich Funktionsparameter so vor, als würden sie von den Attributen eines Objekts getrennt.Profis könnten dies nutzen, um Klassen mit C-ähnlichen statischen Variablen zu haben. Deshalb ist es am besten, die Standardwerte None zu deklarieren und sie nach Bedarf zu initialisieren:
ergibt:
anstelle des Unerwarteten:
quelle