web-dev-qa-db-fra.com

Pourquoi ne pas attribuer à une liste vide (par exemple [] = "") une erreur?

Dans python 3.4, je tape

[] = "" 

et cela fonctionne bien, aucune exception n'est levée. Bien sûr, [] n'est pas égal à "" ensuite.

[] = ()

fonctionne également très bien.

"" = []

lève une exception comme prévu cependant,

() = ""

lève une exception comme prévu cependant. Alors que se passe-t-il?

110
Vardd

Vous ne comparez pas pour l'égalité. Vous attribuez .

Python vous permet d'assigner à plusieurs cibles:

foo, bar = 1, 2

affecte les deux valeurs à foo et bar, respectivement. Tout ce dont vous avez besoin est un séquence ou itérable sur le côté droit, et une liste ou un Tuple de noms sur la gauche.

Quand vous faites:

[] = ""

vous avez attribué une séquence vide (les chaînes vides sont toujours des séquences) à une liste de noms vide.

C'est essentiellement la même chose que de faire:

[foo, bar, baz] = "abc"

où vous vous retrouvez avec foo = "a", bar = "b" et baz = "c", mais avec moins de caractères.

Vous ne pouvez pas, cependant, affecter à une chaîne, donc "" Sur le côté gauche d'une affectation ne fonctionne jamais et est toujours une erreur de syntaxe.

Voir la documentation Affectations :

Une instruction d'affectation évalue la liste d'expressions (rappelez-vous qu'il peut s'agir d'une seule expression ou d'une liste séparée par des virgules, cette dernière produisant un tuple) et attribue l'objet résultant unique à chacune des listes cibles, de gauche à droite.

et

L'affectation d'un objet à une liste cible, éventuellement entre parenthèses ou crochets , est définie de manière récursive comme suit.

C'est moi qui souligne.

Cela Python ne renvoie pas une erreur de syntaxe pour la liste vide est en fait un peu un bug! La grammaire officiellement documentée ne permet pas une liste cible vide, et pour le vide () Vous obtenez une erreur. Voir bug 23275 ; il est considéré comme un bug inoffensif:

Le point de départ est de reconnaître que cela existe depuis très longtemps et est inoffensif.

Voir aussi Pourquoi est-il valable d'affecter à une liste vide mais pas à un tuple vide?

132
Martijn Pieters

Il suit les règles Affectations de la documentation,

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)

Si la target list est une liste de cibles séparées par des virgules: L'objet doit être un itérable avec le même nombre d'éléments que de cibles dans la liste cible, et les éléments sont attribués, de gauche à à droite, vers les cibles correspondantes.

L'objet doit être une séquence avec le même nombre d'éléments que de cibles dans la liste des cibles, et les éléments sont affectés, de gauche à droite, aux cibles correspondantes.

Alors, quand tu dis

[] = ""

"" est un itérable (toute chaîne valide python est un itérable) et il est décompressé sur les éléments de la liste.

Par exemple,

>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')

Puisque vous avez une chaîne vide et une liste vide, il n'y a rien à décompresser. Donc, pas d'erreur.

Mais essayez ceci

>>> [] = "1"
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack

Dans le [] = "1" cas, vous essayez de décompresser la chaîne "1" sur une liste de variables vide. Il se plaint donc de "trop ​​de valeurs à décompresser (0 attendu)".

De même, dans [a] = "" cas, vous avez une chaîne vide, donc rien à décompresser vraiment, mais vous la décompressez sur une variable, ce qui, encore une fois, n'est pas possible. C'est pourquoi il se plaint "besoin de plus de 0 valeurs pour déballer".

En dehors de cela, comme vous l'avez remarqué,

>>> [] = ()

ne génère également aucune erreur, car () est un Tuple vide.

>>> ()
()
>>> type(())
<class 'Tuple'>

et quand il est déballé sur une liste vide, il n'y a rien à déballer. Donc pas d'erreur.


Mais quand tu le fais

>>> "" = []
  File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
  File "<input>", line 1
SyntaxError: can't assign to literal

comme l'indique le message d'erreur, vous essayez d'affecter à un littéral de chaîne. Ce qui n'est pas possible. C'est pourquoi vous obtenez les erreurs. C'est comme dire

>>> 1 = "one"
  File "<input>", line 1
SyntaxError: can't assign to literal

Internes

En interne, cette opération d'affectation sera traduite en UNPACK_SEQUENCE code op,

>>> dis(compile('[] = ""', "string", "exec"))
  1           0 LOAD_CONST               0 ('')
              3 UNPACK_SEQUENCE          0
              6 LOAD_CONST               1 (None)

Ici, puisque la chaîne est vide, UNPACK_SEQUENCE déballe 0 fois. Mais quand vous avez quelque chose comme ça

>>> dis(compile('[a, b, c] = "123"', "string", "exec"))
  1           0 LOAD_CONST               0 ('123')
              3 UNPACK_SEQUENCE          3
              6 STORE_NAME               0 (a)
              9 STORE_NAME               1 (b)
             12 STORE_NAME               2 (c)
             15 LOAD_CONST               1 (None)
             18 RETURN_VALUE

la séquence 123 est décompressé dans la pile, de droite à gauche. Ainsi, le haut de la pile serait 1 et le suivant serait 2 et le dernier serait 3. Ensuite, il attribue une à une les variables du haut de la pile aux variables de l'expression de gauche.


BTW, en Python, voici comment vous pouvez effectuer plusieurs affectations dans la même expression. Par exemple,

a, b, c, d, e, f = u, v, w, x, y, z

cela fonctionne car, les valeurs de droite sont utilisées pour construire un Tuple et ensuite il sera décompressé sur les valeurs de gauche.

>>> dis(compile('a, b, c, d, e, f = u, v, w, x, y, z', "string", "exec"))
  1           0 LOAD_NAME                0 (u)
              3 LOAD_NAME                1 (v)
              6 LOAD_NAME                2 (w)
              9 LOAD_NAME                3 (x)
             12 LOAD_NAME                4 (y)
             15 LOAD_NAME                5 (z)
             18 BUILD_Tuple              6
             21 UNPACK_SEQUENCE          6
             24 STORE_NAME               6 (a)
             27 STORE_NAME               7 (b)
             30 STORE_NAME               8 (c)
             33 STORE_NAME               9 (d)
             36 STORE_NAME              10 (e)
             39 STORE_NAME              11 (f)
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE

mais la technique d'échange classique a, b = b, a utilise la rotation des éléments en haut de la pile. Si vous n'avez que deux ou trois éléments, ils sont traités avec des --- ROT_TWO et ROT_THREE instructions au lieu de construire le Tuple et de le déballer.

>>> dis(compile('a, b = b, a', "string", "exec"))
  1           0 LOAD_NAME                0 (b)
              3 LOAD_NAME                1 (a)
              6 ROT_TWO
              7 STORE_NAME               1 (a)
             10 STORE_NAME               0 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
36
thefourtheye