Żadna z odpowiedzi tutaj nie daje żadnego kodu do pracy, aby naprawdę zilustrować, dlaczego tak się dzieje w krainie Python. I fajnie jest patrzeć głębiej, więc proszę bardzo.
Głównym powodem, dla którego nie działa to tak, jak się spodziewasz, jest to, że podczas pisania w Pythonie:
i += 1
nie robi tego, co myślisz. Liczby całkowite są niezmienne. Można to zobaczyć, patrząc na obiekt znajdujący się w Pythonie:
a = 0
print('ID of the first integer:', id(a))
a += 1
print('ID of the first integer +=1:', id(a))
Funkcja id reprezentuje unikalną i stałą wartość obiektu w czasie jego życia. Pod względem koncepcyjnym luźno mapuje na adres pamięci w C / C ++. Uruchamianie powyższego kodu:
ID of the first integer: 140444342529056
ID of the first integer +=1: 140444342529088
Oznacza to, że pierwszy a
nie jest już taki sam jak drugia
, ponieważ ich identyfikatory są różne. W rzeczywistości znajdują się w różnych miejscach w pamięci.
Z przedmiotem jednak wszystko działa inaczej. Zastąpiłem +=
tutaj operatora:
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))
Uruchomienie tego powoduje następujące wyniki:
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
Zauważ, że atrybut id w tym przypadku jest w rzeczywistości taki sam dla obu iteracji, nawet jeśli wartość obiektu jest inna (możesz również znaleźć id
wartość int, którą posiada obiekt, który zmieniałby się w miarę mutacji - ponieważ liczby całkowite są niezmienne).
Porównaj to z uruchomieniem tego samego ćwiczenia z niezmiennym obiektem:
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))
To daje:
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
Kilka rzeczy do zauważenia. Po pierwsze, w pętli z +=
nie dodajesz już do oryginalnego obiektu. W tym przypadku, ponieważ ints należą do niezmiennych typów w Pythonie , python używa innego identyfikatora. Warto również zauważyć, że Python używa tego samego instrumentu bazowego id
dla wielu zmiennych o tej samej niezmiennej wartości:
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 ma garść niezmiennych typów, które powodują zachowanie, które widzisz. Dla wszystkich typów zmiennych twoje oczekiwania są poprawne.
i
jest niezmienne lub przeprowadzasz niemutującą operację. Z zagnieżdżoną listąfor i in a: a.append(1)
miałoby inne zachowanie; Python nie kopiuje zagnieżdżonych list. Jakkolwiek liczby całkowite są niezmienne, a dodawanie zwraca nowy obiekt, nie zmienia to starego.