Жодна з відповідей тут не дає вам жодного коду для роботи, щоб дійсно проілюструвати, чому це відбувається на землі 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
Тут можна помітити кілька речей. По-перше, у циклі з символом +=
ви більше не додаєте до початкового об'єкта. У цьому випадку, оскільки int є одними з незмінних типів у 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 не копіює вкладені списки. Однак цілі числа незмінні і додавання повертає новий об'єкт, він не змінює старого.