Welcher Stil für nicht verwendete Rückgabeparameter in einem Python-Funktionsaufruf verwendet werden soll

30

Gibt es einen empfohlenen / allgemein akzeptierten Codierungsstil für Situationen, in denen eine Funktion ein Tupel von Werten zurückgibt, aber anschließend nur einer dieser Werte verwendet wird (beachten Sie, dass dies hauptsächlich für Bibliotheksfunktionen gedacht ist, die ich nicht ändern kann - einen Wrapper schreiben Der Anruf ist wahrscheinlich ein bisschen übertrieben ...)? Anstatt zu tun

a, b, c = foo()

und dann einfach nicht bund verwenden c, welche der folgenden Varianten sollte bevorzugt werden (oder gibt es eine andere?):

Variante 1 (Unterstrich)

a, _, _ = foo()

(Das ist sehr klar und einfach, kann aber _ = gettext.gettextin vielen Anwendungen, die Übersetzungen verwenden, zu Konflikten führen. )

Variante 2 (Dummy-Name)

a, unused, unused = foo()

(nicht sehr ansprechend, denke ich, dasselbe gilt für andere Namen wie dummy)

Variante 3 (Index)

a = foo()[0]

(für mich ()[0]sieht das unpythonisch aus ...)

user49643
quelle
Im Gegensatz zu meiner früheren Antwort, was passiert mit Variante 3, wenn Sie jetzt 2/3 der Rückgabewerte referenzieren möchten? Ich habe meine Antwort entfernt, weil mir klar wurde, dass ich nicht genug über Python wusste, um es zu rechtfertigen.
Craige
@Craige: Ich habe deine Antwort nicht gesehen, bevor du sie entfernt hast ... Fragst du, ob a, b = foo()[0:2]sie funktionieren würde? Wenn ja: ja, tut es :)
user49643
Genau das habe ich gefragt. Wenn das funktioniert (wie Sie sagten), würde ich Variante 3 verwenden. Mit diesen Informationen stelle ich meine Antwort wieder her.
Craige
3
Übrigens können Sie heutzutage die ziemlich schöne Syntax für 'erweitertes' Entpacken verwenden : a, *_ = foo()wirft alle Werte außer dem ersten weg.
Benjamin Hodgson
Duplikat von stackoverflow.com/questions/431866/…
Trevor Boyd Smith

Antworten:

17

Die Verwendung des Unterstrichs für nicht verwendete Variablen ist definitiv akzeptabel. Seien Sie jedoch gewarnt, in einigen Codebasen ist dies keine Option, da dieser Bezeichner als Kurzform für reserviert ist gettext. Dies ist der häufigste Einwand gegen diesen Stil (obwohl er, soweit ich das beurteilen kann, für die Mehrheit kein Problem darstellt). Ich würde es immer noch empfehlen und es immer selbst verwenden.

Namen wie dummyoder unusedneigen dazu, mich persönlich zu irritieren, und ich sehe sie nicht so oft (in Python also - ich kenne eine Delphi-Codebasis, die sich dummygroßzügig nutzt , und sie ist auch in Skripten gelandet, die mit dem fraglichen Programm verknüpft sind). Ich würde dir davon abraten.

Es ist auch in Ordnung, nur einen Eintrag aus dem zurückgegebenen Tupel zu extrahieren. Es spart auch Ärger, wenn die Anzahl der nicht verwendeten Werte richtig eingestellt wird. Beachten Sie jedoch, dass es zwei mögliche Nachteile hat:

  • Es explodiert nicht, wenn die Anzahl der Werte von Ihren Erwartungen abweicht. Dies kann nützlich sein, um Verwechslungen und Tippfehler zu erkennen.
  • Es funktioniert nur, wenn der Rückgabewert eine Sequenz ist (das sind meistens Tupel und Listen, aber bleiben wir allgemein). Aus dem Nichts kenne ich eine Klasse in meinem Code (einen 2D-Vektor), die iterierbar ist und eine konstante Anzahl von Werten liefert (und daher beim Auspacken von Zuweisungen verwendet werden kann), die jedoch nicht indexierbar ist.

quelle
Ich habe tatsächlich gettext in meiner Frage erwähnt :) Wie auch immer, ich habe Ihre Antwort akzeptiert - es scheint, dass es keinen eindeutigen akzeptierten Einzelstil gibt, aber Ihre Antwort hat einige interessante Punkte aufgeworfen.
user49643
Um Probleme mit gettext zu vermeiden (oder um ähnliche Probleme im Interpreter zu vermeiden), können Sie doppelte Unterstriche (auch Dunder genannt) anstelle der einzelnen verwenden.
ZIM
21

Pylint hat es mir zur Gewohnheit gemacht, es so zu machen:

widget, _parent, _children = f()

Das heißt, nicht verwendete Ergebnisse haben einen beschreibenden Namen mit dem Präfix _. Pylint betrachtet Einheimische mit dem Präfix _ als nicht verwendet und Globale oder Attribute mit dem Präfix _ als privat.

Vincent Povirk
quelle
3

Wenn Sie dies in Ihrem gesamten Projekt nur einmal oder sehr selten für die jeweilige Funktion tun, würde ich Variante 1 verwenden, wenn Sie wissen, gettextdass in diesem Modul kein Problem vorliegt , und ansonsten Variante 3.

Wenn Sie dies häufig tun - und insbesondere, wenn Sie jedes Mal eine andere Teilmenge der Rückgabewerte benötigen (indem Sie einen Wrapper so einstellen, dass nur die zurückgegeben werden, die Sie für unzuverlässig halten), kann es von Vorteil sein, einen Wrapper zu schreiben Dadurch werden die Ergebnisse in ein benanntes Tupel oder in eine Instanz einer anderen beschreibenden Klasse geschrieben, mit der Sie Folgendes ausführen können:

bar = foo()

Und dann arbeiten mit bar.a, bar.bund bar.c.

lvc
quelle
2

Wie andere gesagt haben, ist Unterstrich ( _) der Standard. Wenn jedoch ein Unterstrich für Übersetzungen verwendet wird, ist der doppelte Unterstrich meiner Meinung nach die beste Alternative.

var, __, value = "VAR=value".partition('=')

Besser als diese:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')

Rick Mohr
quelle
1

Ich bin kein Python-Programmierer, aber für mich ist die dritte Variante am sinnvollsten.

In Variante 3 ist Ihnen absolut klar, mit welchen Werten Sie sich beschäftigen möchten. In Variante 1 und 2 weisen Sie die Werte wieder Variablen zu und können sie somit verwenden. Sie haben sie vielleicht dunkel benannt, aber eine schlechte Benennung ist keine Lösung für ein Problem.

Warum sollten Sie aus Gründen der Übersichtlichkeit einem Steckplatz im Speicher nicht verwendete Werte zuweisen (wie in den Varianten 1 und 2)? Dies wäre eine schlechte Lösung für die Speicherverwaltung.

Craige
quelle
Wenn Sie es immer auf dieselbe Variable setzen, hat das Speicherproblem dann nicht immer nur die Größe einer einzelnen Variablen? Ich denke nicht, dass das ein Problem sein sollte.
Michael McQuade
-2

Hier ist eine allgemeine Regel: Wenn nur 1 der zurückgegebenen Werte verwendet wird, warum nicht einfach diesen 1-Wert zurückgeben? Wenn das Flag von mehreren Stellen aus aufgerufen wird, behalten Sie ein Flag für den gleichen Wert bei und geben Sie Werte zurück, die dem Flag entsprechen.

BEARBEITEN:

Wäre ich in Ihrer Situation und hätte ich die Funktion nicht geschrieben, würde ich vielleicht Variante 2 wählen. Ich würde die Dummy-Namen dort belassen, damit die Parameter bei Bedarf verwendet werden können. Das Schneiden einer Liste ist mit einem gewissen Aufwand verbunden. Vielleicht können Sie ein paar Bytes sparen, um die unerwünschten Daten zu empfangen.

c0da
quelle
-1 Ich vermute, er hat die Funktion nicht definiert und kann daher nicht ändern, was sie zurückgibt. Ich denke, er bezieht sich auf, wenn die Funktion 3 Werte zurückgibt, aber er kümmert sich nur um 1 in seinem aktuellen Anwendungsfall.
Craige
@Craige: Ja, ich habe Funktionen gemeint, die ich nicht ändern konnte. Ich habe meiner Frage einen Hinweis hinzugefügt, der das verdeutlicht.
user49643
Sind Sie sich über den Aufwand sicher? Ich habe einen sehr einfachen Ipython-Test ausprobiert: %timeit a, _, _ = foo()vs. %timeit a = foo()[0], was 123ns vs. 109ns ergab, dh das Schneiden scheint tatsächlich schneller zu sein als das Auspacken des Wertes. Oder hatten Sie eine bestimmte Situation im Sinn?
user49643
2
Ein weiteres plausibles Szenario ist, dass Sie für einige Aufrufe nicht alle Werte benötigen .
Keith Thompson