Aucune des réponses ici ne vous donne de code à utiliser pour illustrer vraiment pourquoi cela se produit en terre Python. Et c'est amusant à regarder dans une approche plus profonde, alors voilà.
La principale raison pour laquelle cela ne fonctionne pas comme prévu est parce qu'en Python, lorsque vous écrivez:
i += 1
il ne fait pas ce que vous pensez qu'il fait. Les entiers sont immuables. Cela peut être vu lorsque vous regardez ce qu'est réellement l'objet en Python:
a = 0
print('ID of the first integer:', id(a))
a += 1
print('ID of the first integer +=1:', id(a))
La fonction id représente une valeur unique et constante pour un objet au cours de sa durée de vie. Conceptuellement, il mappe de manière lâche à une adresse mémoire en C / C ++. Exécution du code ci-dessus:
ID of the first integer: 140444342529056
ID of the first integer +=1: 140444342529088
Cela signifie que le premier a
n'est plus le même que le second a
, car leurs identifiants sont différents. En fait, ils se trouvent à différents endroits de la mémoire.
Avec un objet, cependant, les choses fonctionnent différemment. J'ai remplacé l' +=
opérateur ici:
class CustomInt:
def __iadd__(self, other):
# Override += 1 for this class
self.value = self.value + other.value
return self
def __init__(self, v):
self.value = v
ints = []
for i in range(5):
int = CustomInt(i)
print('ID={}, value={}'.format(id(int), i))
ints.append(int)
for i in ints:
i += CustomInt(i.value)
print("######")
for i in ints:
print('ID={}, value={}'.format(id(i), i.value))
L'exécution de cette opération entraîne la sortie suivante:
ID=140444284275400, value=0
ID=140444284275120, value=1
ID=140444284275064, value=2
ID=140444284310752, value=3
ID=140444284310864, value=4
######
ID=140444284275400, value=0
ID=140444284275120, value=2
ID=140444284275064, value=4
ID=140444284310752, value=6
ID=140444284310864, value=8
Notez que l'attribut id dans ce cas est en fait le même pour les deux itérations, même si la valeur de l'objet est différente (vous pouvez également trouver la id
valeur int de l'objet, qui changerait au fur et à mesure de sa mutation - car les entiers sont immuables).
Comparez cela à lorsque vous exécutez le même exercice avec un objet immuable:
ints_primitives = []
for i in range(5):
int = i
ints_primitives.append(int)
print('ID={}, value={}'.format(id(int), i))
print("######")
for i in ints_primitives:
i += 1
print('ID={}, value={}'.format(id(int), i))
print("######")
for i in ints_primitives:
print('ID={}, value={}'.format(id(i), i))
Cela produit:
ID=140023258889248, value=0
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
######
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
ID=140023258889408, value=5
######
ID=140023258889248, value=0
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
Quelques choses ici à remarquer. Tout d'abord, dans la boucle avec le +=
, vous n'ajoutez plus à l'objet d'origine. Dans ce cas, comme les entiers font partie des types immuables de Python , python utilise un identifiant différent. Il est également intéressant de noter que Python utilise le même sous-jacent id
pour plusieurs variables avec la même valeur immuable:
a = 1999
b = 1999
c = 1999
print('id a:', id(a))
print('id b:', id(b))
print('id c:', id(c))
id a: 139846953372048
id b: 139846953372048
id c: 139846953372048
tl; dr - Python a une poignée de types immuables, qui provoquent le comportement que vous voyez. Pour tous les types mutables, votre attente est correcte.
i
est immuable ou si vous effectuez une opération sans mutation. Avec une liste imbriquéefor i in a: a.append(1)
aurait un comportement différent; Python ne copie pas les listes imbriquées. Cependant, les entiers sont immuables et l'addition renvoie un nouvel objet, il ne change pas l'ancien.