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