Zignoruj ​​wielokrotne zwracane wartości w Pythonie

274

Powiedzmy, że mam funkcję Python, która zwraca wiele wartości w krotce:

def func():
    return 1, 2

Czy istnieje dobry sposób na zignorowanie jednego z wyników zamiast przypisywania go do zmiennej tymczasowej? Powiedz, że gdybym był zainteresowany tylko pierwszą wartością, czy istnieje lepszy sposób niż ten:

x, temp = func()
Mata
źródło
2
Ciekawe, że to też pochodzi z podobnego pojęcia Matlaba dotyczącego ignorowania danych wyjściowych funkcji, w których używają one ~składni do ignorowania określonej zmiennej zwracanej
jxramos
3
Jako rozwiązanie wybrałeś złą odpowiedź
AGP

Odpowiedzi:

241

Jedną z powszechnych konwencji jest użycie „_” jako nazwy zmiennej dla elementów krotki, które chcesz zignorować. Na przykład:

def f():
    return 1, 2, 3

_, _, x = f()
Brian Clapper
źródło
89
-1: ta „konwencja” jest do kitu, gdy dodajesz funkcję gettext do kodu innej osoby (która definiuje funkcję o nazwie „_”), więc powinna zostać zbanowana
nosklo 11.01.2009
27
Dobra uwaga - choć dyskusyjne jest, czy naleganie gettext na instalację funkcji o nazwie „ ” jest dobrym pomysłem. Osobiście uważam to za trochę brzydkie. Niezależnie od tego użycie „ ” jako zmiennej odchodzącej jest powszechne.
Brian Clapper
25
-1: _ oznacza „ostatnie wyjście” w IPython. Nigdy bym tego nie przypisał.
endolith
20
Ok, nie zauważyłem „ja” - dzięki za referencje. IMHO nie możesz oczekiwać, że inni nie będą używać zmiennej tylko dlatego, że jedna aplikacja Python definiuje dla niej swoje magiczne zastosowanie.
Draemon
8
niektóre IDE, takie jak PyDev, ostrzegają o tym, ponieważ masz nieużywane zmienne.
teeks99,
593

Możesz użyć x = func()[0]do zwrócenia pierwszej wartości, x = func()[1]do zwrócenia drugiej itd.

Jeśli chcesz uzyskać wiele wartości jednocześnie, użyj czegoś takiego x, y = func()[2:4].

Luke Woodward
źródło
92
To powinna być zaakceptowana odpowiedź. Możesz także użyć takich rzeczy, jak func()[2:4]jeśli chcesz tylko niektóre zwracane wartości.
endolith,
11
Nie wywołuje funkcji wiele razy: >>> def test (): ... wydrukuj "tutaj" ... zwróć 1,2,3 ... >>> a, b = test () [: 2 ] tutaj [edytuj: przepraszam, że kod się nie pojawił, najwyraźniej masz tylko jeden wiersz w komentarzach. Dla tych, którzy nie znają >>> i ... są początek nowej linii w powłoce pytona]
teeks99
32
@TylerLong: Myślę, że _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func()jest mniej jasne niż wielokrotne wywoływanie funkcji, ale to tylko moja opinia. Jeśli twoja funkcja zwraca tyle pozycji, myślę, że lepiej byłoby użyć numpy:a, b, c, d, e = func()[[13, 25, 58, 89, 98]]
endolith
24
@endolith Myślę, że to jest lepsze i nie wymaga numpy i nie musi wywoływać func () wiele razy: result = func() a = result[13] b = result[25]...
Tyler Long
3
Ten styl nie jest miły, jeśli chcesz zignorować jedną lub kilka wartości pomiędzy, np.x, __, y = func()
ndemou
96

Jeśli używasz Python 3, możesz użyć gwiazdki przed zmienną (po lewej stronie przypisania), aby była to lista podczas rozpakowywania.

# 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
źródło
2
Możesz także użyć a, *_ = f()do zignorowania dowolnej liczby zwracanych wartości po a.
THN
21

Pamiętaj, że kiedy zwracasz więcej niż jeden przedmiot, naprawdę zwracasz krotkę. Możesz więc robić takie rzeczy:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2
Evan Fosmark
źródło
17

Powszechną praktyką jest używanie zmiennej fikcyjnej _ (pojedynczy podkreślnik), jak wiele osób wskazało tutaj wcześniej.

Jednak, aby uniknąć kolizji z innymi zastosowaniami tej nazwy zmiennej (patrz ta odpowiedź), lepszym rozwiązaniem może być użycie __(podwójnego podkreślenia) zamiast zmiennej odchodzącej , jak wskazuje ncoghlan . Na przykład:

x, __ = func()
mdły
źródło
Niezły pomysł. Ale wtedy „_ _” zadeklaruje zmienną w przestrzeni nazw. Natomiast „_” nie jest deklarowane, chyba że zostanie użyte specjalnie po lewej stronie instrukcji przypisania, jak powyżej (np a, _, _ = 1,8,9.:). Do tego momentu przechowuje wynik ostatniej wykonanej instrukcji, który jeśli chcesz złapać, zwykle używasz zmiennej do przechowywania tej wartości. I dlatego „_” jest sugerowaną nazwą zmiennej, która ma przechwytywać niepotrzebne wartości. Wartości „_” zostaną zastąpione wkrótce po wykonaniu innej instrukcji. W przypadku „_ _” wartość pozostanie tam, dopóki GC go nie usunie.
Archit Kapoor
16

Trzy proste opcje.

Oczywisty

x, _ = func()

x, junk = func()

Ohydny

x = func()[0]

I są sposoby, aby to zrobić za pomocą dekoratora.

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

func0= val0(func)
S.Lott
źródło
5
Naprawdę wolę _zmienną. To oczywiste, że ignorujesz wartość
Claudiu
21
Twoje przykłady są wsteczne. x, _ = func()jest ohydny i x = func()[0]oczywisty. Przypisywanie do zmiennej, a następnie jej nie używanie? Funkcja zwraca krotkę; indeksuj to jak krotkę.
endolith
6
W językach dopasowywania wzorców, z których Python wyprowadził ten wzorzec, metoda „oczywista” jest rzeczywiście oczywista, nie ohydna i kanoniczna. Chociaż w takich językach symbol wieloznaczny jest obsługiwaną funkcją języka, podczas gdy w Pythonie jest to prawdziwa zmienna i zostaje powiązana, co jest trochę niesmaczne.
Joe
4
List przetwarzania języków, z których pochodzą Pythona ;)lista dostępowe, takie jak a[0], a[:](lista kopii), a[::2](co dwa elementy) i a[i:] + a[:i](Obrót liście), są w istocie również oczywiste kanonicznych.
cod3monk3y
7

Prawdopodobnie najlepszym rozwiązaniem jest nazywanie rzeczy zamiast zwracania bezsensownych krotek. Chyba że za kolejnością zwracanych przedmiotów kryje się jakaś logika.

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

latitude = func()['lat']

Możesz nawet użyć namedtuple, jeśli chcesz dodać dodatkowe informacje o tym, co zwracasz (to nie jest tylko słownik, to są współrzędne):

from collections import namedtuple 

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

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

latitude = func().lat

Jeśli obiekty w twoim słowniku / krotce są ściśle ze sobą powiązane, dobrym pomysłem może być nawet zdefiniowanie dla niej klasy. W ten sposób będziesz mógł zdefiniować interakcję między obiektami tego typu i podać interfejs API, jak z nimi pracować. Naturalne pytanie: Kiedy powinienem używać klas w Pythonie? .

cglacet
źródło
4

To wydaje mi się najlepszym wyborem:

val1, val2, ignored1, ignored2 = some_function()

Nie jest tajemniczy ani brzydki (jak metoda func () [index]) i wyraźnie określa twój cel.

kmelvn
źródło
4

To nie jest bezpośrednia odpowiedź na pytanie. Raczej odpowiada na to pytanie: „Jak wybrać konkretną funkcję z wielu możliwych opcji?”.

Jeśli jesteś w stanie napisać funkcję (tzn. Nie ma jej w bibliotece, której nie można zmodyfikować), dodaj argument wejściowy wskazujący, czego chcesz od funkcji. Zrób z niej nazwany argument o wartości domyślnej, aby w „zwykłym przypadku” nawet nie musieć go podawać.

    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 )

Ta metoda daje funkcji „zaawansowane ostrzeżenie” dotyczące pożądanego wyjścia. W rezultacie może ominąć niepotrzebne przetwarzanie i wykonać tylko pracę niezbędną do uzyskania pożądanego wyniku. Ponieważ Python wykonuje dynamiczne pisanie, typ zwracany może się zmienić. Zauważ, jak przykład zwraca skalar, listę lub krotkę ... cokolwiek chcesz!

1-ijk
źródło
2

Jeśli jest to funkcja, której używasz cały czas, ale zawsze odrzucasz drugi argument, argumentowałbym, że mniej bałagan jest tworzenie aliasu dla funkcji bez użycia drugiej wartości zwracanej lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Chrigi
źródło
2

Jeśli masz wiele danych wyjściowych z funkcji i nie chcesz wywoływać jej wiele razy, myślę, że najlepszym sposobem na wybranie wyników byłoby:

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

Jako minimum działający przykład, pokazujący, że funkcja jest wywoływana tylko raz:

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]]

A wartości są zgodne z oczekiwaniami:

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

Dla wygody można również użyć indeksów list w języku Python:

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

Zwraca: a = 3 ib = 12

jeannej
źródło