Ни один из ответов здесь не дает вам никакого кода для работы, чтобы действительно проиллюстрировать, почему это происходит на земле Python. И это интересно смотреть на более глубокий подход, так что здесь идет.
Основная причина того, что это не работает так, как вы ожидаете, заключается в том, что в Python, когда вы пишете:
i += 1
это не делает то, что вы думаете, что делает. Целые числа неизменны. Это можно увидеть, когда вы посмотрите, что на самом деле представляет собой объект в Python:
a = 0
print('ID of the first integer:', id(a))
a += 1
print('ID of the first integer +=1:', id(a))
Функция id представляет собой уникальное и постоянное значение для объекта в его жизни. Концептуально он слабо сопоставляется с адресом памяти в C / C ++. Выполнение приведенного выше кода:
ID of the first integer: 140444342529056
ID of the first integer +=1: 140444342529088
Это означает, что первое a
больше не совпадает со вторым a
, потому что их идентификаторы разные. Фактически они находятся в разных местах памяти.
Однако с объектом все работает иначе. Я переписал +=
оператор здесь:
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))
Выполнение этого приводит к следующему выводу:
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
Обратите внимание, что атрибут id в этом случае фактически одинаков для обеих итераций, даже если значение объекта различно (вы также можете найти id
значение int, которое содержит объект, которое будет меняться по мере его изменения - потому что целые числа неизменны).
Сравните это с тем, когда вы выполняете то же упражнение с неизменным объектом:
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))
Это выводит:
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
Несколько вещей здесь, чтобы заметить. Во-первых, в цикле с +=
, вы больше не добавляете к исходному объекту. В этом случае, поскольку целые числа входят в число неизменяемых типов в Python , python использует другой идентификатор. Также интересно отметить, что Python использует один и тот же базовый элемент id
для нескольких переменных с одинаковым неизменным значением:
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 имеет несколько неизменяемых типов, которые вызывают поведение, которое вы видите. Для всех изменчивых типов ваше ожидание верное.
i
является неизменным или вы выполняете операцию без мутаций. С вложенным спискомfor i in a: a.append(1)
было бы другое поведение; Python не копирует вложенные списки. Однако целые числа неизменны, и сложение возвращает новый объект, но не меняет старый.