Ignorer la valeur de retour multiple python

275

Disons que j'ai une fonction Python qui renvoie plusieurs valeurs dans un tuple:

def func():
    return 1, 2

Existe-t-il un bon moyen d'ignorer l'un des résultats plutôt que de simplement l'affecter à une variable temporaire? Dites si je n'étais intéressé que par la première valeur, y a-t-il un meilleur moyen que celui-ci:

x, temp = func()
Tapis
la source
2
Je suis aussi curieux de savoir que cela vient de la notion similaire de Matlab d' ignorer les sorties de fonction où ils utilisent ~comme syntaxe pour ignorer une variable de retour particulière
jxramos
3
Vous avez sélectionné la mauvaise réponse comme solution
AGP

Réponses:

243

Une convention courante consiste à utiliser un "_" comme nom de variable pour les éléments du tuple que vous souhaitez ignorer. Par exemple:

def f():
    return 1, 2, 3

_, _, x = f()
Brian Clapper
la source
89
-1: cette "convention" craint lorsque vous ajoutez la fonctionnalité gettext au code de quelqu'un d'autre (qui définit une fonction appelée '_') donc elle doit être interdite
nosklo
27
Bon point - bien que l'on puisse se demander si l'insistance de gettext à installer une fonction appelée " " est une bonne idée. Personnellement, je trouve ça un peu moche. Quoi qu'il en soit, l'utilisation de " " comme variable jetable est répandue.
Brian Clapper
25
-1: _ signifie "dernière sortie" en IPython. Je ne lui attribuerais jamais quelque chose.
endolith
20
D'accord, je n'ai pas remarqué le "je" - merci pour la référence. À mon humble avis, vous ne pouvez pas vous attendre à ce que les autres n'utilisent pas une variable simplement parce qu'une application Python définit sa propre utilisation magique.
Draemon
8
certains IDE tels que PyDev vous donneront un avertissement à ce sujet, car vous avez des variables inutilisées.
teeks99
597

Vous pouvez utiliser x = func()[0]pour renvoyer la première valeur, x = func()[1]pour renvoyer la seconde, etc.

Si vous souhaitez obtenir plusieurs valeurs à la fois, utilisez quelque chose comme x, y = func()[2:4].

Luke Woodward
la source
92
Ce devrait être la réponse acceptée. Vous pouvez également utiliser des choses comme func()[2:4]si vous ne voulez que certaines des valeurs de retour.
endolith
11
Il n'appelle pas la fonction plusieurs fois: >>> def test (): ... print "here" ... return 1,2,3 ... >>> a, b = test () [: 2 ] ici [modifier: désolé que le code ne soit pas passé, apparemment vous n'obtenez qu'une seule ligne dans les commentaires. Pour ceux qui ne sont pas familiers >>> et ... sont le début d'une nouvelle ligne dans le shell python]
teeks99
32
@TylerLong: Je pense que _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func()c'est moins clair que d'appeler la fonction plusieurs fois, mais c'est juste mon avis. Si votre fonction renvoie autant d'éléments, je pense que l'utilisation de numpy serait préférable:a, b, c, d, e = func()[[13, 25, 58, 89, 98]]
endolith
24
@endolith Je pense que c'est mieux et n'a pas besoin de numpy et n'a pas besoin d'appeler func () plusieurs fois: result = func() a = result[13] b = result[25]...
Tyler Long
3
Ce style n'est pas agréable lorsque vous voulez ignorer une ou quelques valeurs entre les deux, par exemplex, __, y = func()
ndemou
96

Si vous utilisez Python 3, vous pouvez utiliser l'étoile devant une variable (sur le côté gauche d'une affectation) pour qu'elle soit une liste dans le déballage.

# 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
la source
2
Vous pouvez également utiliser a, *_ = f()pour ignorer le nombre arbitraire de valeurs renvoyées après a.
THN
21

N'oubliez pas que lorsque vous retournez plusieurs articles, vous retournez vraiment un tuple. Vous pouvez donc faire des choses comme ça:

def func():
    return 1, 2

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

La pratique courante consiste à utiliser la variable fictive _(soulignement simple), comme beaucoup l'ont indiqué précédemment.

Cependant, pour éviter les collisions avec d'autres utilisations de ce nom de variable (voir cette réponse), il pourrait être préférable d'utiliser __(double soulignement) à la place comme variable jetable , comme indiqué par ncoghlan . Par exemple:

x, __ = func()
apathique
la source
Pas du tout une mauvaise idée. Mais alors '_ _' déclarerait une variable dans l'espace de noms. Alors que '_' ne déclare pas sauf s'il est spécifiquement utilisé sur le côté gauche de l'instruction d'affectation comme ci-dessus (par exemple:) a, _, _ = 1,8,9. Jusque-là, il stocke le résultat de la dernière instruction exécutée qui, si vous voulez intercepter, vous utiliseriez normalement une variable pour stocker cette valeur. Et c'est pourquoi, '_' est le nom de variable suggéré pour attraper les valeurs indésirables. Les valeurs '_' sont écrasées peu de temps après l'exécution d'une autre instruction. En cas de '_ _', la valeur resterait là jusqu'à ce que GC la nettoie.
Archit Kapoor
16

Trois choix simples.

Évident

x, _ = func()

x, junk = func()

Hideux

x = func()[0]

Et il existe des moyens de le faire avec un décorateur.

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

func0= val0(func)
S.Lott
la source
5
Je préfère vraiment la _variable. Il est très évident que vous ignorez une valeur
Claudiu
21
Vos exemples sont à l'envers. x, _ = func()est hideux et x = func()[0]évident. Assigner à une variable et ne pas l'utiliser ensuite? La fonction renvoie un tuple; indexez-le comme un tuple.
endolith
6
Dans les langages d'appariement de motifs, dont Python a dérivé ce motif, la méthode «évidente» est en effet évidente, pas hideuse et canonique. Bien que, dans de telles langues, le caractère générique soit une fonctionnalité de langue prise en charge alors qu'en Python, c'est une vraie variable et est liée, ce qui est un peu désagréable.
Joe
4
Pour les langages de traitement de liste, dont Python est dérivé ;), les accesseurs de liste tels que a[0], a[:](copie de liste), a[::2](tous les deux éléments) et a[i:] + a[:i](rotation d'une liste), sont en effet également évidents et canoniques.
cod3monk3y
7

La meilleure solution est probablement de nommer les choses au lieu de renvoyer des tuples sans signification. Sauf s'il y a une certaine logique derrière l'ordre des articles retournés.

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

latitude = func()['lat']

Vous pouvez même utiliser namedtuple si vous souhaitez ajouter des informations supplémentaires sur ce que vous retournez (ce n'est pas seulement un dictionnaire, ce sont des coordonnées):

from collections import namedtuple 

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

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

latitude = func().lat

Si les objets de votre dictionnaire / tuple sont fortement liés, il peut être judicieux de même définir une classe pour lui. De cette façon, vous pourrez également définir l'interaction entre des objets de ce type et donner une API sur la façon de travailler avec eux. Une question naturelle qui suit: Quand devrais-je utiliser des classes en Python? .

cglacet
la source
4

Cela me semble être le meilleur choix:

val1, val2, ignored1, ignored2 = some_function()

Ce n'est pas cryptique ou laid (comme la méthode func () [index]), et indique clairement votre objectif.

kmelvn
la source
4

Ce n'est pas une réponse directe à la question. Il répond plutôt à cette question: "Comment choisir une sortie de fonction spécifique parmi de nombreuses options possibles?".

Si vous pouvez écrire la fonction (c'est-à-dire qu'elle ne se trouve pas dans une bibliothèque que vous ne pouvez pas modifier), ajoutez un argument d'entrée qui indique ce que vous voulez retirer de la fonction. Faites-en un argument nommé avec une valeur par défaut afin que dans le "cas commun" vous n'ayez même pas à le spécifier.

    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 )

Cette méthode donne la fonction "avertissement avancé" concernant la sortie souhaitée. Par conséquent, il peut ignorer le traitement inutile et ne faire que le travail nécessaire pour obtenir la sortie souhaitée. De plus, parce que Python effectue une frappe dynamique, le type de retour peut changer. Remarquez comment l'exemple retourne un scalaire, une liste ou un tuple ... tout ce que vous aimez!

1-ijk
la source
2

S'il s'agit d'une fonction que vous utilisez tout le temps mais que vous rejetez toujours le deuxième argument, je dirais qu'il est moins compliqué de créer un alias pour la fonction sans la deuxième valeur de retour à l'aide lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Chrigi
la source
2

Lorsque vous avez plusieurs sorties d'une fonction et que vous ne voulez pas l'appeler plusieurs fois, je pense que la manière la plus claire de sélectionner les résultats serait:

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

Comme exemple de travail minimum, démontrant également que la fonction n'est appelée qu'une seule fois:

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

Et les valeurs sont comme prévu:

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

Pour plus de commodité, les index de liste Python peuvent également être utilisés:

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

Renvoie: a = 3 et b = 12

jeannej
la source