Ignorar valor de retorno múltiplo do python

274

Digamos que eu tenho uma função Python que retorna vários valores em uma tupla:

def func():
    return 1, 2

Existe uma boa maneira de ignorar um dos resultados, em vez de apenas atribuir a uma variável temporária? Digamos que se eu estivesse interessado apenas no primeiro valor, existe uma maneira melhor do que isso:

x, temp = func()
Esteira
fonte
2
Fiquei curioso deste demasiado vindo noção semelhante de Matlab de Ignorar Função Saídas onde eles usam ~como a sintaxe para ignorar uma variável de retorno especial
jxramos
3
Você selecionou a resposta errada como solução
AGP

Respostas:

242

Uma convenção comum é usar um "_" como um nome de variável para os elementos da tupla que você deseja ignorar. Por exemplo:

def f():
    return 1, 2, 3

_, _, x = f()
Brian Clapper
fonte
89
-1: este "convenção" suga quando você adiciona funcionalidade gettext para código de outra pessoa (que define uma função chamada '_'), por isso deve ser proibida
nosklo
27
Bom ponto - embora seja discutível se a insistência do gettext em instalar uma função chamada " " é uma boa idéia. Pessoalmente, acho um pouco feio. Independentemente, o uso de " " como uma variável descartável é generalizada.
Brian Clapper
25
-1: _ significa "última saída" no IPython. Eu nunca atribuiria algo a isso.
endolith
20
Ok, eu não percebi o "eu" - obrigado pela referência. IMHO, você não pode esperar que outros não usem uma variável apenas porque um aplicativo Python define seu próprio uso mágico para ela.
Draemon
8
alguns IDEs, como o PyDev, alertam sobre isso, porque você tem variáveis ​​não utilizadas.
precisa saber é o seguinte
595

Você pode usar x = func()[0]para retornar o primeiro valor,x = func()[1] retornar o segundo e assim por diante.

Se você deseja obter vários valores por vez, use algo como x, y = func()[2:4].

Luke Woodward
fonte
92
Essa deve ser a resposta aceita. Você também pode usar coisas como func()[2:4]se você quiser apenas alguns dos valores de retorno.
endolith
11
Ele não chama a função várias vezes: >>> def test (): ... print "here" ... retorna 1,2,3 ... >>> a, b = test () [: 2 ] aqui [edit: desculpe pelo código não ter aparecido, aparentemente você só tem uma linha nos comentários. Para aqueles que não estão familiarizados >>> e ... são o início de uma nova linha no shell python]
teeks99
32
@TylerLong: Eu acho que _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func()é menos claro do que chamar a função várias vezes, mas essa é apenas a minha opinião. Se a sua função retornos que muitos itens, acho que usando numpy seria preferível:a, b, c, d, e = func()[[13, 25, 58, 89, 98]]
endolith
24
@endolith Eu acho que isso é melhor e não precisa de numpy e não precisa func call () várias vezes: result = func() a = result[13] b = result[25]...
Tyler longo
3
Esse estilo não é bom quando você deseja ignorar um ou alguns valores intermediários, por exemplo,x, __, y = func()
ndemou
96

Se você estiver usando o Python 3, poderá usar a estrela antes de uma variável (no lado esquerdo de uma atribuição) para que seja uma lista na descompactação.

# 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
fonte
2
Você também pode usar a, *_ = f()para ignorar o número arbitrário de valores retornados depois a.
THN
21

Lembre-se, quando você devolve mais de um item, está realmente retornando uma tupla. Então você pode fazer coisas assim:

def func():
    return 1, 2

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

A prática comum é usar a variável dummy _(sublinhado único), como muitos indicaram aqui antes.

No entanto, para evitar colisões com outros usos desse nome de variável (consulte esta resposta), pode ser uma prática melhor usar __(sublinhado duplo) como uma variável descartável, conforme apontado por ncoghlan . Por exemplo:

x, __ = func()
sem graça
fonte
Não é uma má idéia. Mas então '_ _' declararia uma variável no espaço para nome. Visto que '_' não declara, a menos que seja especificamente usado no lado esquerdo da instrução de atribuição como acima (por exemplo a, _, _ = 1,8,9:). Até esse ponto, ele armazena o resultado da última instrução executada que, se você quiser capturar, normalmente usaria uma variável para armazenar esse valor. E é por isso que '_' é o nome da variável sugerido para capturar valores de lixo eletrônico. Os valores '_' são substituídos logo após a execução de outra instrução. No caso de '_ _', o valor permaneceria lá até que o GC o limpasse.
Archit Kapoor
16

Três escolhas simples.

Óbvio

x, _ = func()

x, junk = func()

Hediondo

x = func()[0]

E há maneiras de fazer isso com um decorador.

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

func0= val0(func)
S.Lott
fonte
5
Eu realmente prefiro a _variável. É muito óbvio que você está ignorando um valor
Claudiu
21
Seus exemplos são invertidos. x, _ = func()é hediondo e x = func()[0]óbvio. Atribuindo a uma variável e depois não a usando? A função está retornando uma tupla; indexe-o como uma tupla.
endolith 26/03
6
Nas linguagens de correspondência de padrões, das quais Python derivou esse padrão, o método 'óbvio' é realmente óbvio, não hediondo e canônico. Embora, nessas linguagens, o curinga seja um recurso de linguagem suportada, enquanto no Python é uma variável real e fica vinculada, o que é um pouco desagradável.
31413 Joe
4
Para idiomas lista de processamento, a partir do qual é derivado o Python ;), lista acessores, tais como a[0], a[:](cópia lista), a[::2](cada dois elementos), e a[i:] + a[:i](girar uma lista), são, de facto, também óbvio e canónica.
Cod3monk3y
7

A melhor solução provavelmente é nomear as coisas em vez de retornar tuplas sem sentido. A menos que haja alguma lógica por trás da ordem dos itens devolvidos.

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

latitude = func()['lat']

Você pode até usar o nomeado duplo se desejar adicionar informações extras sobre o que está retornando (não é apenas um dicionário, são coordenadas):

from collections import namedtuple 

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

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

latitude = func().lat

Se os objetos no seu dicionário / tupla estiverem fortemente ligados, pode ser uma boa ideia definir uma classe para ele. Dessa forma, você também poderá definir a interação entre objetos desse tipo e fornecer uma API sobre como trabalhar com eles. Uma pergunta natural a seguir: Quando devo usar classes em Python? .

cglacet
fonte
4

Esta parece ser a melhor escolha para mim:

val1, val2, ignored1, ignored2 = some_function()

Não é enigmático ou feio (como o método func () [index]) e indica claramente seu objetivo.

kmelvn
fonte
4

Esta não é uma resposta direta à pergunta. Em vez disso, responde a esta pergunta: "Como escolho uma saída de função específica dentre muitas opções possíveis?".

Se você conseguir escrever a função (ou seja, ela não estiver em uma biblioteca que não possa ser modificada), adicione um argumento de entrada que indique o que você deseja da função. Crie um argumento nomeado com um valor padrão para que, no "caso comum", você nem precise especificá-lo.

    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 fornece a função "aviso avançado" em relação à saída desejada. Conseqüentemente, ele pode pular o processamento desnecessário e fazer apenas o trabalho necessário para obter a saída desejada. Também porque o Python faz digitação dinâmica, o tipo de retorno pode mudar. Observe como o exemplo retorna um escalar, uma lista ou uma tupla ... o que você quiser!

1-ijk
fonte
2

Se essa é uma função que você usa o tempo todo, mas sempre descarta o segundo argumento, eu diria que é menos confuso criar um alias para a função sem o segundo valor de retorno usando lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Chrigi
fonte
2

Quando você tem muitos resultados de uma função e não deseja chamá-lo várias vezes, acho que a maneira mais clara de selecionar os resultados seria:

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

Como um exemplo de trabalho mínimo, também demonstrando que a função é chamada apenas uma 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]]

E os valores são os esperados:

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

Por conveniência, os índices da lista Python também podem ser usados:

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

Retorna: a = 3 eb = 12

jeannej
fonte