134 votes

Déballage, déballage étendu et déballage étendu imbriqué

Tenir compte de ces expressions... s'il vous Plaît être patient... la liste est bien LONGUE...

(Note: certaines expressions sont répétées -- c'est juste pour présenter un "contexte")

a, b = 1, 2 # séquence simple affectation
a, b = ['vert', 'bleu'] # liste asqignment
a, b = 'XY' # affectation de chaîne
a, b = range(1,5,2) # un objet iterable fera


 # séquence imbriquée affectation

(a,b), c = "XY", "Z" # a = 'X', b = Y, c = 'Z' 

(a,b), c = "XYZ" # ERREUR -- trop de valeurs pour décompresser
(a,b), c = "XY" # ERREUR -- besoin de plus de 1 valeur pour décompresser

(a,b), c, = [1,2], "ceci" # a = '1', b = '2', c = 'ce'
(a,b), (c,) = [1,2],'ce' # ERREUR -- trop de valeurs pour décompresser


 # séquence prolongée déballage

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

a, *b = 'X' # a = 'X', b = []
*a, b = 'X' # a = [], b = 'X'
a, *b, c = "XY" # a = 'X', b = [], c = 'Y'
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'

a, b, *c = 1,2,3 # a = 1, b = 2, c = [3]
a, b, c, *d = 1,2,3 # a = 1, b = 2, c = 3, d = []

a, *b, c, *d = 1,2,3,4,5 # ERREUR -- deux étoilé expressions dans l'affectation

(a,b), c = [1,2], "ceci" # a = '1', b = '2', c = 'ce'
(a,b) *c = [1,2], "ceci" # a = '1', b = '2', c = ['ce']

(a,b), c, *d = [1,2], "ceci" # a = '1', b = '2', c = 'ceci', d = []
(a,b), *c, d = [1,2], "ceci" # a = '1', b = '2', c = [], d = 'ce'

(a,b), (c, *d) = [1,2], "ceci" # a = '1', b = '2', c = 't', d = ['h', 'i', 's']

*un = 1 # ERREUR, la cible doit être une liste ou un tuple
*un = (1,2) # ERREUR, la cible doit être une liste ou un tuple
*a, = (1,2) # a = [1,2]
*a, = 1 # ERREUR -- 'int' object n'est pas itérable
*un, = [1] # a = [1]
*a = [1] # ERREUR, la cible doit être une liste ou un tuple
*a, = (1,) # a = [1]
*a, = (1) # ERREUR -- 'int' object n'est pas itérable

*a, b = [1] # a = [], b = 1
*a, b = (1,) # a = [], b = 1

(a,b),c = 1,2,3 # ERREUR -- trop de valeurs pour décompresser
(a,b) *c = 1,2,3 d'ERREUR # - 'int' object n'est pas itérable
(a,b) *c = 'XY', 2, 3 # a = 'X', b = Y, c = [2,3]


 # séquence prolongée déballage -- IMBRIQUÉE

(a,b),c = 1,2,3 # ERREUR -- trop de valeurs pour décompresser
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3

*(a,b) = 1,2 # ERREUR, la cible doit être une liste ou un tuple
*(a,b) = 1,2 # a = 1, b = 2

*(a,b) = 'XY' # ERREUR, la cible doit être une liste ou un tuple
*(a,b) = 'XY' # a = 'X', b = 'Y'

*(a, b) = 'ce' # ERREUR, la cible doit être une liste ou un tuple
*(a, b) = 'ce' # ERREUR -- trop de valeurs pour décompresser
*a, *b), = 'ce' # a = 't', b = ['h', 'i', 's']

*a, *b), c = 'ce' # a = 't', b = ['h', 'i'], c = 's'

*a,*b), = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6, 7]

*a,*b) *c = 1,2,3,3,4,5,6,7 # ERREUR -- deux étoilé expressions dans l'affectation
*a,*b), (b*c) = 1,2,3,3,4,5,6,7 # ERREUR -- 'int' object n'est pas itérable
*a,*b), c = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6], c = 7
*a,*b), (b*c) = 1,2,3,4,5,'XY' # a = 1, b = [2, 3, 4, 5], c = ['X', 'Y']

*a,*b), c, d = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5], c = 6, d = 7
*a,*b), (c, d) = 1,2,3,3,4,5,6,7 # ERREUR -- 'int' object n'est pas itérable
*a,*b, *c, d) = 1,2,3,3,4,5,6,7 # ERREUR -- 'int' object n'est pas itérable
*a,*b) *(c, d) = 1,2,3,3,4,5,6,7 # ERREUR -- deux étoilé expressions dans l'affectation


*(a,b), c = 'XY', 3 # ERREUR -- besoin de plus de 1 valeur pour décompresser
*(*a,b), c = 'XY', 3 # a = [], b = 'XY', c = 3
(a,b), c = 'XY', 3 # a = 'X', b = Y, c = 3

*(a,b), c = 'XY', 3, 4 # a = 'XY', b = 3, c = 4
*(*a,b), c = 'XY', 3, 4 # a = ['XY'], b = 3, c = 4
(a,b), c = 'XY', 3, 4 # ERREUR -- trop de valeurs pour décompresser

MERCI pour votre PATIENCE :)

Maintenant mes questions est: comment comprendre une telle complexité et de la confusion. Comment on peut être toujours à DROITE, lors du calcul des résultats de ces expressions à la main. Ou, lors de la lecture de quelqu'un d'autre code, dois-je simplement de les ignorer et de ne jamais essayer d'imaginer à quoi l'expression est en train de faire?

140voto

senderle Points 41607

Mes excuses pour la longueur de ce post, mais j'ai décidé d'opter pour l'exhaustivité.

Une fois que vous savez quelques règles de base, il n'est pas difficile de les généraliser. Je vais faire de mon mieux pour expliquer à l'aide de quelques exemples. Puisque vous parlez de l'évaluation de ces "par la main", je vous suggère quelques simples règles de substitution. Fondamentalement, vous pouvez trouver plus facile de comprendre une expression si tous les iterables sont formatés de la même façon.

Pour les fins de déballage seulement, les substitutions suivantes sont valables sur le côté droit de l' = (c'est à dire pour les rvalues):

'XY' -> ('X', 'Y')
['X', 'Y'] -> ('X', 'Y')

Si vous trouvez qu'une valeur à ne pas avoir déballé, alors vous aurez à l'annulation de la substitution. (Voir ci-dessous pour plus d'explications.)

Aussi, quand vous voyez "nu", de virgules, de faire semblant, il y a un haut niveau de tuple. Ce faire à la fois à gauche et à droite (c'est à dire pour lvalues et rvalues):

'X', 'Y' -> ('X', 'Y')
a, b -> (a, b)

Avec ces règles simples à l'esprit, voici quelques exemples:

(a,b), c = "XY", "Z"                 # a = 'X', b = 'Y', c = 'Z'

En appliquant les règles ci-dessus, nous convertir "XY" de ('X', 'Y'), et de couvrir la nudité des virgules dans les parenthèses:

((a, b), c) = (('X', 'Y'), 'Z')

La correspondance visuelle ici, il est assez évident que la cession des œuvres.

Voici une fausse exemple:

(a,b), c = "XYZ"

À la suite de la substitution de règles, nous obtenons le ci-dessous:

((a, b), c) = ('X', 'Y', 'Z')

C'est clairement erronée; les structures imbriquées ne correspondent pas. Maintenant, nous allons voir comment cela fonctionne pour un exemple légèrement plus complexe:

(a,b), c, = [1,2],'this'             # a = '1', b = '2', c = 'this'

En appliquant les règles ci-dessus, nous obtenons

((a, b), c) = ((1, 2), ('t', 'h', 'i', 's'))

Mais maintenant, il est clair à partir de la structure qui l' 'this' ne sera pas déballé, mais affectés directement à l' c. Nous avons donc à l'annulation de la substitution.

((a, b), c) = ((1, 2), 'this')

Maintenant, nous allons voir ce qui se passe lorsque nous envelopper c dans un tuple:

(a,b), (c,) = [1,2],'this'           # ERROR -- too many values to unpack

Devient

((a, b), (c,)) = ((1, 2), ('t', 'h', 'i', 's'))

Encore une fois, l'erreur est évidente. c n'est plus un nu variable, mais une variable à l'intérieur d'une séquence, et donc la séquence correspondant sur la droite est déballé en (c,). Mais les séquences ont une longueur différente, donc il y a une erreur.

Maintenant, pour de longues déballage à l'aide de l' * de l'opérateur. C'est un peu plus complexe, mais c'est encore assez simple. Une variable précédée d' * devient une liste qui contient tous les éléments de la séquence correspondant qui ne sont pas affectés à des noms de variables. Départ assez simple exemple:

a, *b, c = "X...Y"                   # a = 'X', b = ['.','.','.'], c = 'Y'

Cela devient

(a, *b, c) = ('X', '.', '.', '.', 'Y')

La façon la plus simple d'analyser ce qui est de travailler à partir des extrémités. 'X' est attribué à l' a et 'Y' est attribué à l' c. Les valeurs restantes dans la séquence sont mis dans une liste et affectée à l' b.

Lvalues comme (*a, b) et (a, *b) sont juste des cas spéciaux de la ci-dessus. Vous ne pouvez pas avoir les deux * des opérateurs à l'intérieur de l'une lvalue séquence parce qu'il serait ambigu. Où en seraient les valeurs vont en quelque chose comme cela, (a, *b, *c, d) -- en b ou c? Je vais envisager l'étude cas dans un instant.

*a = 1                               # ERROR -- target must be in a list or tuple

Ici, l'erreur est assez explicite. La cible (*a) doit être dans un tuple.

*a, = (1,2)                          # a = [1,2]

Cela fonctionne parce qu'il y a nu par des virgules. L'application des règles...

(*a,) = (1, 2)

Depuis il n'y a pas de variables autres que l' *a, *a slurps toutes les valeurs dans la rvalue séquence. Si vous remplacez l' (1, 2) , avec une seule valeur?

*a, = 1                              # ERROR -- 'int' object is not iterable

devient

(*a,) = 1

Encore une fois, l'erreur ici est auto-explicatif. Vous ne pouvez pas décompresser quelque chose qui n'est pas un ordre, et *a besoin de quelque chose pour décompresser. Nous avons donc mis dans une séquence

*a, = [1]                            # a = [1]

Qui est eqivalent à

(*a,) = (1,)

Enfin, c'est un point commun de confusion: (1) est le même que 1 -- vous besoin d'une virgule pour distinguer un tuple à partir d'un énoncé arithmétique.

*a, = (1)                            # ERROR -- 'int' object is not 

Maintenant pour la nidification. En fait cet exemple n'est pas dans votre "NICHE" de la section; peut-être que vous ne savais pas que c'était imbriqué?

(a,b), *c = 'XY', 2, 3               # a = 'X', b = 'Y', c = [2,3]

Devient

((a, b), *c) = (('X', 'Y'), 2, 3)

La première valeur dans le haut-niveau n-uplet est affectée, et les valeurs restantes dans le haut-niveau n-uplet (2 et 3) sont affectés à l' c -- tout comme on devrait s'attendre.

(a,b),c = 1,2,3                      # ERROR -- too many values to unpack
*(a,b), c = 1,2,3                    # a = 1, b = 2, c = 3

Je l'ai déjà expliqué plus haut pourquoi la première ligne renvoie une erreur. La deuxième ligne est idiot mais voici pourquoi il fonctionne:

(*(a, b), c) = (1, 2, 3)

Comme expliqué précédemment, nous travaillons à partir des extrémités. 3 est attribué à l' c, et puis les autres valeurs sont affectées à la variable avec l' * qui le précède, dans ce cas, (a, b). Donc, c'est équivalent à (a, b) = (1, 2), ce qui arrive à travailler parce qu'il y a le bon nombre d'éléments. Je ne peux pas penser à une raison quelconque, ce serait d'apparaître dans le code du travail.

Quelques exemples:

*(a, *b), c = 'this'                 # a = 't', b = ['h', 'i'], c = 's'

devient

(*(a, *b), c) = ('t', 'h', 'i', 's')

Travail à partir des extrémités, 's' est attribué à l' c, et ('t', 'h', 'i') est attribué à l' (a, *b). Travailler à nouveau à partir des extrémités, 't' est attribué à l' a, et ('h', 'i') est attribué à b comme une liste. C'est un autre exemple stupide qui ne doit jamais apparaître dans le code du travail.

7voto

agf Points 45052

Je trouve le Python 2 n-uplet déballage assez simple. Chaque nom sur la gauche correspond à une séquence entière ou un seul élément dans une séquence sur la droite. Si les noms correspondent à des éléments uniques de n'importe quelle séquence, alors il doit y avoir assez de noms pour couvrir tous les éléments.

Étendue déballage, cependant, peut certainement être source de confusion, car il est si puissant. La réalité est que vous ne devriez jamais faire le dernier 10 ou plus valide les exemples que vous avez donné -- si les données sont structurées, il devrait être dans un dict ou une instance de classe, pas de formes non structurées comme des listes.

Clairement, la nouvelle syntaxe peuvent être victimes de violence. La réponse à votre question est que vous ne devriez pas avoir à lire des expressions comme ça, ils sont d'une mauvaise pratique et je doute qu'ils vont être utilisés.

Juste parce que vous pouvez écrire arbitrairement complexes expressions ne signifie pas que vous devriez. Vous pourriez écrire du code comme celui - map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables)) mais vous n'avez pas.

4voto

Michał Šrajer Points 9487

Si vous pensez que votre code peut être trompeur, utilisez un autre formulaire pour l'exprimer.

C'est comme utiliser des crochets supplémentaires dans les expressions pour éviter les questions sur la priorité des opérateurs. C'est toujours un bon investissement pour rendre votre code lisible.

Je préfère utiliser le déballage uniquement pour des tâches simples comme l'échange.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X