Ignorieren Sie den Mehrfachrückgabewert von Python

273

Angenommen, ich habe eine Python-Funktion, die mehrere Werte in einem Tupel zurückgibt:

def func():
    return 1, 2

Gibt es eine gute Möglichkeit, eines der Ergebnisse zu ignorieren, anstatt es nur einer temporären Variablen zuzuweisen? Sagen Sie, wenn ich nur am ersten Wert interessiert war, gibt es einen besseren Weg als diesen:

x, temp = func()
Matte
quelle
2
Ich wurde auch neugierig , weil Matlab eine ähnliche Vorstellung von Funktionsausgängen ignorieren hatte, bei der sie ~als Syntax zum Ignorieren einer bestimmten Rückgabevariablen verwendet wurden
jxramos
3
Sie haben die falsche Antwort als Lösung ausgewählt
AGP

Antworten:

241

Eine übliche Konvention besteht darin, ein "_" als Variablennamen für die Elemente des Tupels zu verwenden, die Sie ignorieren möchten. Zum Beispiel:

def f():
    return 1, 2, 3

_, _, x = f()
Brian Clapper
quelle
89
-1: Diese "Konvention" ist zum Kotzen, wenn Sie dem Code einer anderen Person gettext-Funktionalität hinzufügen (die eine Funktion namens '_' definiert), sodass sie
gesperrt
27
Guter Punkt - obwohl es fraglich ist, ob gettext darauf besteht, eine Funktion namens " " zu installieren, ist eine gute Idee. Ich persönlich finde es etwas hässlich. Unabhängig davon ist die Verwendung von " " als Wegwerfvariable weit verbreitet.
Brian Clapper
25
-1: _ bedeutet "letzte Ausgabe" in IPython. Ich würde ihm niemals etwas zuweisen.
Endolith
20
Ok, ich habe das "Ich" nicht bemerkt - danke für den Hinweis. IMHO können Sie nicht erwarten, dass andere keine Variable verwenden, nur weil eine Python-App ihre eigene magische Verwendung dafür definiert.
Draemon
8
Einige IDEs wie PyDev geben Ihnen eine Warnung, da Sie nicht verwendete Variablen haben.
Teeks99
593

Sie können verwenden x = func()[0], um den ersten Wert zurückzugeben, x = func()[1]um den zweiten zurückzugeben und so weiter.

Wenn Sie mehrere Werte gleichzeitig erhalten möchten, verwenden Sie so etwas wie x, y = func()[2:4].

Luke Woodward
quelle
92
Dies sollte die akzeptierte Antwort sein. Sie können auch Dinge verwenden, func()[2:4]wenn Sie nur einige der Rückgabewerte möchten .
Endolith
11
Die Funktion wird nicht mehrmals aufgerufen: >>> def test (): ... print "here" ... return 1,2,3 ... >>> a, b = test () [: 2 ] hier [bearbeiten: Entschuldigung, dass der Code nicht durchgekommen ist. Anscheinend erhalten Sie nur eine Zeile in den Kommentaren. Für diejenigen, die nicht vertraut sind >>> und ... sind der Beginn einer neuen Zeile in der Python-Shell]
teeks99
32
@ TylerLong: Ich denke, es _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func()ist weniger klar als die Funktion mehrmals aufzurufen, aber das ist nur meine Meinung. Wenn Ihre Funktion so viele Elemente zurückgibt, ist die Verwendung von numpy meiner Meinung nach vorzuziehen:a, b, c, d, e = func()[[13, 25, 58, 89, 98]]
Endolith
24
@endolith Ich denke, das ist besser und braucht nicht numpy und muss nicht mehrmals func () aufrufen: result = func() a = result[13] b = result[25]...
Tyler Long
3
Dieser Stil ist nicht schön, wenn Sie einen oder mehrere Werte dazwischen ignorieren möchten, z. B.x, __, y = func()
ndemou
96

Wenn Sie Python 3 verwenden, können Sie den Stern vor einer Variablen (auf der linken Seite einer Zuweisung) verwenden, damit diese beim Entpacken als Liste angezeigt wird.

# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]
Joe
quelle
2
Sie können auch eine a, *_ = f()beliebige Anzahl von zurückgegebenen Werten nach ignorieren a.
THN
21

Denken Sie daran, wenn Sie mehr als einen Artikel zurückgeben, geben Sie wirklich ein Tupel zurück. Sie können also Folgendes tun:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2
Evan Fosmark
quelle
17

Es ist üblich, die Dummy-Variable _(einzelner Unterstrich) zu verwenden, wie viele hier bereits angegeben haben.

Um jedoch Kollisionen mit anderen Verwendungen dieses Variablennamens zu vermeiden (siehe diese Antwort), ist es möglicherweise besser, __stattdessen (doppelter Unterstrich) als Wegwerfvariable zu verwenden , wie von ncoghlan angegeben . Z.B:

x, __ = func()
lackadaisical
quelle
Keine schlechte Idee. Aber dann würde '_ _' eine Variable im Namespace deklarieren. Während '_' nicht deklariert, es sei denn, es wird speziell auf der linken Seite der Zuweisungsanweisung wie oben verwendet (zB :) a, _, _ = 1,8,9. Bis zu diesem Zeitpunkt wird das Ergebnis der zuletzt ausgeführten Anweisung gespeichert. Wenn Sie abfangen möchten, verwenden Sie normalerweise eine Variable, um diesen Wert zu speichern. Aus diesem Grund ist '_' der vorgeschlagene Variablenname zum Abfangen von Junk-Werten. '_' Werte werden überschrieben, sobald eine andere Anweisung ausgeführt wird. Im Fall von '_ _' bleibt der Wert dort, bis GC ihn bereinigt.
Archit Kapoor
16

Drei einfache Möglichkeiten.

Offensichtlich

x, _ = func()

x, junk = func()

Schrecklich

x = func()[0]

Und es gibt Möglichkeiten, dies mit einem Dekorateur zu tun.

def val0( aFunc ):
    def pick0( *args, **kw ):
        return aFunc(*args,**kw)[0]
    return pick0

func0= val0(func)
S.Lott
quelle
5
Ich bevorzuge die _Variable wirklich . Es ist sehr offensichtlich, dass Sie einen Wert ignorieren
Claudiu
21
Ihre Beispiele sind rückwärts. x, _ = func()ist abscheulich und x = func()[0]offensichtlich. Einer Variablen zuweisen und dann nicht verwenden? Die Funktion gibt ein Tupel zurück. indiziere es wie ein Tupel.
Endolith
6
In Mustervergleichssprachen, von denen Python dieses Muster abgeleitet hat, ist die "offensichtliche" Methode in der Tat offensichtlich, nicht abscheulich und kanonisch. In solchen Sprachen ist der Platzhalter zwar eine unterstützte Sprachfunktion, während er in Python eine echte Variable ist und gebunden wird, was ein wenig unangenehm ist.
Joe
4
Listen Verarbeitung Sprachen, von denen Python abgeleitet ist ;), Accessoren Liste wie a[0], a[:](Liste kopieren), a[::2](alle zwei Elemente) und a[i:] + a[:i](drehen , um eine Liste), ist in der Tat, auch offensichtlich , und kanonisch.
cod3monk3y
7

Die beste Lösung besteht wahrscheinlich darin, Dinge zu benennen, anstatt bedeutungslose Tupel zurückzugeben. Es sei denn, hinter der Reihenfolge der zurückgegebenen Artikel steht eine Logik.

def func():
    return {'lat': 1, 'lng': 2}

latitude = func()['lat']

Sie können sogar namedtuple verwenden, wenn Sie zusätzliche Informationen zu Ihrer Rückgabe hinzufügen möchten (es handelt sich nicht nur um ein Wörterbuch, sondern um Koordinaten):

from collections import namedtuple 

Coordinates = namedtuple('Coordinates', ['lat', 'lng'])

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

Wenn die Objekte in Ihrem Wörterbuch / Tupel stark miteinander verbunden sind, ist es möglicherweise eine gute Idee, sogar eine Klasse dafür zu definieren. Auf diese Weise können Sie auch die Interaktion zwischen Objekten dieses Typs definieren und eine API für die Arbeit mit ihnen angeben. Eine natürliche Frage, die folgt: Wann sollte ich Klassen in Python verwenden? .

cglacet
quelle
4

Dies scheint mir die beste Wahl zu sein:

val1, val2, ignored1, ignored2 = some_function()

Es ist nicht kryptisch oder hässlich (wie die Methode func () [index]) und gibt Ihren Zweck klar an.

kmelvn
quelle
4

Dies ist keine direkte Antwort auf die Frage. Vielmehr beantwortet es diese Frage: "Wie wähle ich eine bestimmte Funktionsausgabe aus vielen möglichen Optionen aus?".

Wenn Sie die Funktion schreiben können (dh sie befindet sich nicht in einer Bibliothek, die Sie nicht ändern können), fügen Sie ein Eingabeargument hinzu, das angibt, was Sie von der Funktion erwarten. Machen Sie es zu einem benannten Argument mit einem Standardwert, damit Sie es im "allgemeinen Fall" nicht einmal angeben müssen.

    def fancy_function( arg1, arg2, return_type=1 ):
        ret_val = None
        if( 1 == return_type ):
            ret_val = arg1 + arg2
        elif( 2 == return_type ):
            ret_val = [ arg1, arg2, arg1 * arg2 ]
        else:
            ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 ) 
        return( ret_val )

Diese Methode gibt die Funktion "Erweiterte Warnung" bezüglich der gewünschten Ausgabe. Folglich kann es unnötige Verarbeitung überspringen und nur die Arbeit erledigen, die erforderlich ist, um die gewünschte Ausgabe zu erhalten. Da Python dynamisch tippt, kann sich auch der Rückgabetyp ändern. Beachten Sie, wie das Beispiel einen Skalar, eine Liste oder ein Tupel zurückgibt ... was auch immer Sie möchten!

1-ijk
quelle
2

Wenn dies eine Funktion ist, die Sie ständig verwenden, aber immer das zweite Argument verwerfen, würde ich argumentieren, dass es weniger umständlich ist, einen Alias ​​für die Funktion zu erstellen, ohne dass der zweite Rückgabewert verwendet wird lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Chrigi
quelle
2

Wenn Sie viele Ausgaben von einer Funktion haben und diese nicht mehrmals aufrufen möchten, ist meiner Meinung nach der klarste Weg zur Auswahl der Ergebnisse:

results = fct()
a,b = [results[i] for i in list_of_index]

Als Mindestarbeitsbeispiel wird auch gezeigt, dass die Funktion nur einmal aufgerufen wird:

def fct(a):
    b=a*2
    c=a+2
    d=a+b
    e=b*2
    f=a*a
    print("fct called")
    return[a,b,c,d,e,f]

results=fct(3)
> fct called

x,y = [results[i] for i in [1,4]]

Und die Werte sind wie erwartet:

results
> [3,6,5,9,12,9]
x
> 6
y
> 12

Zur Vereinfachung können auch Python-Listenindizes verwendet werden:

x,y = [results[i] for i in [0,-2]]

Rückgabe: a = 3 und b = 12

Jeannej
quelle