Ignorar el valor de retorno múltiple de Python

275

Digamos que tengo una función de Python que devuelve múltiples valores en una tupla:

def func():
    return 1, 2

¿Hay una buena manera de ignorar uno de los resultados en lugar de simplemente asignarlo a una variable temporal? Digamos que si solo me interesara el primer valor, ¿hay una mejor manera que esta?

x, temp = func()
Estera
fuente
2
Tengo curiosidad de que esto también provenga de la noción similar de Matlab de Ignorar salidas de función donde se usan ~como sintaxis para ignorar una variable de retorno particular
jxramos
3
Seleccionó la respuesta incorrecta como solución
AGP

Respuestas:

243

Una convención común es usar una "_" como nombre de variable para los elementos de la tupla que desea ignorar. Por ejemplo:

def f():
    return 1, 2, 3

_, _, x = f()
Brian Clapper
fuente
89
-1: esta "convención" apesta cuando agrega la funcionalidad gettext al código de otra persona (que define una función llamada '_'), por lo que debería prohibirse
nosklo
27
Buen punto, aunque es discutible si la insistencia de gettext en instalar una función llamada " " es una buena idea. Personalmente, me parece un poco feo. En cualquier caso, el uso de " " como variable desechable está muy extendido.
Brian Clapper el
25
-1: _ significa "última salida" en IPython. Nunca le asignaría algo.
endolito el
20
Ok, no noté el "yo" - gracias por la referencia. En mi humilde opinión, no puedes esperar que otros no usen una variable solo porque una aplicación de Python define su propio uso mágico.
Draemon
8
algunos IDEs como PyDev le darán una advertencia al respecto, porque tiene variables no utilizadas.
teeks99
596

Puede usar x = func()[0]para devolver el primer valor, x = func()[1]para devolver el segundo, etc.

Si desea obtener múltiples valores a la vez, use algo como x, y = func()[2:4].

Luke Woodward
fuente
92
Esta debería ser la respuesta aceptada. También puede usar cosas como func()[2:4]si solo desea algunos de los valores de retorno.
endolito el
11
No llama a la función varias veces: >>> def test (): ... print "here" ... return 1,2,3 ... >>> a, b = test () [: 2 ] aquí [editar: lo siento, ese código no llegó, aparentemente solo obtienes una línea en los comentarios. Para aquellos que no están familiarizados >>> y ... son el comienzo de una nueva línea en el shell de python]
teeks99
32
@TylerLong: Creo que _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func()es menos claro que llamar a la función varias veces, pero esa es solo mi opinión. Si su función devuelve tantos elementos, creo que sería preferible usar numpy:a, b, c, d, e = func()[[13, 25, 58, 89, 98]]
endolith el
24
@endolith Creo que esto es mejor y no necesita numpy y no necesita llamar a func () varias veces: result = func() a = result[13] b = result[25]...
Tyler Long
3
Este estilo no es agradable cuando desea ignorar uno o algunos valores intermedios, por ejemplox, __, y = func()
ndemou
96

Si está usando Python 3, puede usar la estrella antes de una variable (en el lado izquierdo de una tarea) para que sea una lista en el desempaque.

# 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
fuente
2
También puede usar a, *_ = f()para ignorar el número arbitrario de valores devueltos después a.
THN
21

Recuerde, cuando devuelve más de un artículo, realmente está devolviendo una tupla. Entonces puedes hacer cosas como esta:

def func():
    return 1, 2

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

La práctica común es usar la variable ficticia _(subrayado simple), como muchos han indicado aquí antes.

Sin embargo, para evitar colisiones con otros usos de ese nombre de variable (vea esta respuesta), podría ser una mejor práctica usar __(doble guión bajo) como una variable desechable, como lo señala ncoghlan . P.ej:

x, __ = func()
lánguido
fuente
No es una mala idea del todo. Pero entonces '_ _' declararía una variable en el espacio de nombres. Mientras que '_' no declara a menos que se use específicamente en el lado izquierdo de la declaración de asignación como se indica arriba (por ejemplo:) a, _, _ = 1,8,9. Hasta ese momento, almacena el resultado de la última instrucción ejecutada que, si desea capturar, normalmente usaría una variable para almacenar ese valor. Y esta es la razón por la cual '_' es el nombre de variable sugerido para capturar valores basura. Los valores '_' se sobrescriben poco después de que se ejecute otra instrucción. En el caso de '_ _', el valor permanecería allí hasta que GC lo limpie.
Archit Kapoor
16

Tres elecciones simples.

Obvio

x, _ = func()

x, junk = func()

Horrible

x = func()[0]

Y hay formas de hacer esto con un decorador.

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

func0= val0(func)
S.Lott
fuente
55
Realmente prefiero la _variable. Es muy obvio que estás ignorando un valor
Claudiu el
21
Tus ejemplos son al revés. x, _ = func()es horrible y x = func()[0]es obvio. ¿Asignar a una variable y luego no usarla? La función está devolviendo una tupla; indexarlo como una tupla.
endolito
66
En los lenguajes de coincidencia de patrones, de los cuales Python deriva este patrón, el método 'obvio' es realmente obvio, no horrible y canónico. Aunque, en tales idiomas, el comodín es una característica de lenguaje compatible, mientras que en Python es una variable real y se vincula, lo que es un poco desagradable.
Joe
44
Para los lenguajes de procesamiento de listas, de los cuales se deriva Python ;), los accesos de lista como a[0], a[:](copia de la lista), a[::2](cada dos elementos) y a[i:] + a[:i](rotar una lista), también son evidentes y canónicos.
cod3monk3y
7

La mejor solución probablemente sea nombrar cosas en lugar de devolver tuplas sin sentido. A menos que haya alguna lógica detrás del orden de los artículos devueltos.

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

latitude = func()['lat']

Incluso podría usar namedtuple si desea agregar información adicional sobre lo que está devolviendo (no es solo un diccionario, estas son coordenadas):

from collections import namedtuple 

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

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

latitude = func().lat

Si los objetos dentro de su diccionario / tupla están fuertemente unidos, entonces puede ser una buena idea incluso definir una clase para ello. De esa manera, también podrá definir la interacción entre objetos de este tipo y ofrecer una API sobre cómo trabajar con ellos. Una pregunta natural que sigue: ¿ Cuándo debería usar clases en Python? .

cglacet
fuente
4

Esta me parece la mejor opción:

val1, val2, ignored1, ignored2 = some_function()

No es críptico ni feo (como el método func () [index]), y establece claramente su propósito.

kmelvn
fuente
4

Esta no es una respuesta directa a la pregunta. Más bien responde a esta pregunta: "¿Cómo elijo una salida de función específica de muchas opciones posibles?".

Si puede escribir la función (es decir, no está en una biblioteca que no puede modificar), agregue un argumento de entrada que indique lo que desea de la función. Conviértalo en un argumento con nombre con un valor predeterminado para que en el "caso común" ni siquiera tenga que especificarlo.

    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 )

Este método le da a la función "advertencia avanzada" con respecto a la salida deseada. En consecuencia, puede omitir el procesamiento innecesario y solo hacer el trabajo necesario para obtener el resultado deseado. Además, debido a que Python hace tipeo dinámico, el tipo de retorno puede cambiar. Observe cómo el ejemplo devuelve un escalar, una lista o una tupla ... ¡lo que quiera!

1-ijk
fuente
2

Si esta es una función que usa todo el tiempo pero siempre descarta el segundo argumento, diría que es menos complicado crear un alias para la función sin usar el segundo valor de retorno lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Chrigi
fuente
2

Cuando tiene muchos resultados de una función y no desea llamarla varias veces, creo que la forma más clara de seleccionar los resultados sería:

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

Como ejemplo de trabajo mínimo, también demuestra que la función se llama solo una vez:

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

Y los valores son los esperados:

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

Por conveniencia, los índices de lista de Python también se pueden usar:

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

Devuelve: a = 3 yb = 12

jeannej
fuente