Richtiger Stil für Python-Funktionen, die das Argument mutieren

9

Ich möchte eine Python-Funktion schreiben, die eines der Argumente mutiert (das ist eine Liste, dh änderbar). Etwas wie das:

%Vor%

Ich bin vertrauter mit der Übergabe von Wert als Python-Setup (wie auch immer Sie es nennen möchten). Also würde ich normalerweise eine solche Funktion schreiben:

%Vor%

Hier ist meine Verwirrung. Da ich das Argument einfach mutieren kann, erscheint die zweite Methode überflüssig. Aber der erste fühlt sich falsch an. Außerdem wird meine spezielle Funktion mehrere Parameter haben, von denen sich nur einer ändern wird. Die zweite Methode macht deutlich, welches Argument sich ändert (weil es der Variablen zugewiesen ist). Die erste Methode gibt keinen Hinweis. Gibt es eine Konvention? Welches ist besser'? Danke.

    
Neil Du Toit 24.09.2014, 22:38
quelle

3 Antworten

9

Der erste Weg:

%Vor%

ist der idiomatische Weg, es zu tun. Im Allgemeinen erwarten wir in Python, dass eine Funktion entweder die Argumente mutiert oder etwas zurückgibt 1 . Der Grund dafür ist, dass, wenn eine Funktion nichts zurückgibt, es deutlich macht, dass die Funktion eine gewisse Nebenwirkung hatte, um ihre Existenz zu rechtfertigen (z. B. das Mutieren der Eingaben).

Auf der anderen Seite, wenn Sie die Dinge auf die zweite Art tun:

%Vor%

Sie sind anfällig dafür, Bugs aufzuspüren, bei denen sich ein veränderbares Objekt plötzlich ändert, wenn Sie es nicht erwartet haben - "Aber ich dachte change hat eine Kopie erstellt" ...

1 Technisch liefert jede Funktion etwas zurück, dass _something_ zufälligerweise None ...

ist     
mgilson 24.09.2014, 22:39
quelle
8

Die Konvention in Python ist, dass Funktionen entweder etwas mutieren oder etwas zurückgeben, nicht beides.

Wenn beide nützlich sind, schreiben Sie normalerweise zwei separate Funktionen, wobei der Mutator für ein aktives Verb wie change und der Nicht-Mutator für ein Partizip wie changed benannt ist.

Fast alles in builtins und der stdlib folgt diesem Muster. Die Methode list.append , die Sie aufrufen, gibt nichts zurück. Gleiches mit list.sort -but sorted überlässt das Argument alleine und gibt stattdessen eine neue sortierte Kopie zurück.

Es gibt eine Handvoll Ausnahmen für einige der speziellen Methoden (zB __iadd__ soll mutieren und dann self zurückgeben), und ein paar Fälle, in denen eindeutig eine Sache mutieren muss und ein < em> verschiedene -Dinge werden zurückgegeben (wie list.pop ) und für Bibliotheken, die versuchen, Python als eine Art domänenspezifische Sprache zu verwenden, in der es wichtiger ist, mit den Idiomen der Zieldomäne übereinzustimmen als mit Pythons zu konsistent zu sein Idiome (zB einige SQL-Abfrage-Expression-Bibliotheken). Wie bei allen Konventionen wird diesem gefolgt, es sei denn, es gibt einen guten Grund, dies nicht zu tun.

Also, warum wurde Python so entworfen?

Nun, zum einen macht es bestimmte Fehler offensichtlich. Wenn Sie erwartet haben, dass eine Funktion nicht mutiert und einen Wert zurückgibt, ist es ziemlich offensichtlich, dass Sie sich geirrt haben, denn Sie erhalten einen Fehler wie AttributeError: 'NoneType' object has no attribute 'foo' .

Es macht auch konzeptionellen Sinn: eine Funktion, die nichts zurückgibt, muss Nebenwirkungen haben, oder warum hätte jemand sie geschrieben?

Aber es gibt auch die Tatsache, dass jede Anweisung in Python genau eine Sache mutiert - fast immer das Objekt ganz links in der Anweisung. In anderen Sprachen ist die Zuweisung ein Ausdruck, mutierende Funktionen geben self zurück, und Sie können eine ganze Reihe von Mutationen in eine einzige Codezeile ketten, und das macht es schwieriger, die Zustandsänderungen auf einen Blick zu sehen, Grund für sie im Detail, oder durchlaufen Sie sie in einem Debugger.

Natürlich ist das alles ein Kompromiss - es macht etwas Code in Python etwas ausführlicher als etwa in JavaScript, aber es ist ein Kompromiss, der tief in Pythons Design eingebettet ist.

    
abarnert 24.09.2014 22:54
quelle
1

Es macht kaum Sinn, ein Argument zu mutieren und es zurückzugeben. Es kann nicht nur Verwirrung stiften für diejenigen, die den Code lesen, sondern auch für die veränderbares Standardargument Problem . Wenn das Ergebnis der Funktion nur durch das mutierte Argument erhalten werden kann, ist es nicht sinnvoll, dem Argument einen Standardwert zu geben.

Es gibt eine dritte Option, die Sie in Ihrer Frage nicht angezeigt haben. Anstatt das als Argument übergebene Objekt zu mutieren, erstellen Sie eine Kopie dieses Arguments und geben Sie es stattdessen zurück. Dies macht es zu einer reinen Funktion ohne Nebenwirkungen.

%Vor%     
Mark Ransom 30.06.2016 22:37
quelle

Tags und Links