a = [1, 2, 3]
a[-1] += a.pop()
Cela donne [1, 6]
.
a = [1, 2, 3]
a[0] += a.pop()
Cela donne [4, 2]
. Quel ordre d'évaluation donne ces deux résultats?
a = [1, 2, 3]
a[-1] += a.pop()
Cela donne [1, 6]
.
a = [1, 2, 3]
a[0] += a.pop()
Cela donne [4, 2]
. Quel ordre d'évaluation donne ces deux résultats?
RHS d'abord, puis LHS. Et de n'importe quel côté, l'ordre d'évaluation est de gauche à droite.
a[-1] += a.pop()
est identique à, a[-1] = a[-1] + a.pop()
a = [1,2,3]
a[-1] = a[-1] + a.pop() # a = [1, 6]
Voyez comment le comportement change lorsque nous changeons l'ordre des opérations chez RHS,
a = [1,2,3]
a[-1] = a.pop() + a[-1] # a = [1, 5]
L'idée clé est que l' a[-1] += a.pop()
est sucre syntaxique pour a[-1] = a[-1] + a.pop()
. Cela est vrai parce qu' +=
est appliquée à un objet immuable (un int
ici) plutôt que d'un objet mutable (question pertinente ici).
La droite (D) est évalué en premier. Sur les RHS: l'équivalent de la syntaxe est - a[-1] + a.pop()
. Tout d'abord, a[-1]
obtient la dernière valeur 3
. Deuxièmement, a.pop()
return
s 3
.
3
+ 3
est 6
.
Sur le côté Gauche (LHS), a
est désormais [1,2]
en raison de la mutation est déjà appliqué par list.pop()
et la valeur de a[-1]
est modifié à partir d' 2
de 6
.
Jetons un coup d'oeil à la sortie de l' dis.dis
pour a[-1] += a.pop()
1):
3 15 LOAD_FAST 0 (a) # a,
18 LOAD_CONST 5 (-1) # a, -1
21 DUP_TOP_TWO # a, -1, a, -1
22 BINARY_SUBSCR # a, -1, 3
23 LOAD_FAST 0 (a) # a, -1, 3, a
26 LOAD_ATTR 0 (pop) # a, -1, 3, a.pop
29 CALL_FUNCTION 0 (0 positional, 0 keyword pair) # a, -1, 3, 3
32 INPLACE_ADD # a, -1, 6
33 ROT_THREE # 6, a, -1
34 STORE_SUBSCR # (empty)
La signification des différentes instructions est répertorié ici.
Tout d'abord, LOAD_FAST
et LOAD_CONST
charge a
et -1
sur la pile, et DUP_TOP_TWO
doublons les deux, avant d' BINARY_SUBSCR
obtient l'indice de la valeur, résultant en a, -1, 3
sur la pile. Il charge alors a
nouveau, et LOAD_ATTR
des charges de l' pop
de la fonction, qui est appelé sans argument, en CALL_FUNCTION
. La pile est maintenant a, -1, 3, 3
, et INPLACE_ADD
ajoute les deux valeurs. Enfin, ROT_THREE
tourne la pile d' 6, a, -1
pour correspondre à l'ordre prévu par STORE_SUBSCR
et la valeur est stockée.
Donc, en résumé, la valeur courante de a[-1]
est évaluée avant d'appeler a.pop()
et le résultat de l'addition est ensuite stocké retour à la nouvelle - a[-1]
, indépendamment de sa valeur actuelle.
1) C'est le démontage pour Python 3, légèrement comprimé, afin de mieux l'adapter à la page, avec un ajout de la colonne montrant la pile après l' # ...
; pour Python 2 c'est un peu différent, mais semblable.
À l'aide d'un mince wrapper autour d'une liste avec le débogage d'impression-états peut être utilisé pour montrer l'ordre d'évaluation dans votre cas:
class Test(object):
def __init__(self, lst):
self.lst = lst
def __getitem__(self, item):
print('in getitem', self.lst, item)
return self.lst[item]
def __setitem__(self, item, value):
print('in setitem', self.lst, item, value)
self.lst[item] = value
def pop(self):
item = self.lst.pop()
print('in pop, returning', item)
return item
Lorsque j'ai maintenant exécuter votre exemple:
>>> a = Test([1, 2, 3])
>>> a[-1] += a.pop()
in getitem [1, 2, 3] -1
in pop, returning 3
in setitem [1, 2] -1 6
Donc, il commence par se faire le dernier élément, qui est de 3, puis retire le dernier élément qui est aussi 3, les ajoute et écrase le dernier élément de votre liste avec 6
. De sorte que la liste définitive sera [1, 6]
.
Et dans votre deuxième cas:
>>> a = Test([1, 2, 3])
>>> a[0] += a.pop()
in getitem [1, 2, 3] 0
in pop, returning 3
in setitem [1, 2] 0 4
Cela prend désormais le premier élément (1
) ajoute à la sauté valeur (3
) et remplace le premier élément avec la somme: [4, 2]
.
L'ordre général de l'évaluation est déjà expliqué en @Fallen
et @tobias_k
. Cette réponse juste, complète le principe général mentionné.
Pour vous un exemple précis
a[-1] += a.pop() #is the same as
a[-1] = a[-1] + a.pop() # a[-1] = 3 + 3
Ordre:
a[-1]
après =
pop()
, la diminution de la longueur de l' a
Le truc c'est qu' a[-1]
devient la valeur de a[1]
(a a[2]
) après l' pop()
, mais ce qui se passe avant la cession.
a[0] = a[0] + a.pop()
Fonctionne comme prévu
a[0]
après =
pop()
Cet exemple montre pourquoi vous ne devriez pas manipuler une liste tout en travaillant sur elle (on le dit couramment pour les boucles). Toujours travailler sur copys dans ce cas.
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.