Nessuna delle risposte qui ti dà alcun codice con cui lavorare per illustrare davvero perché ciò accade nella terra di Python. E questo è divertente da guardare in un approccio più profondo, quindi ecco qui.
Il motivo principale per cui questo non funziona come previsto è perché in Python, quando scrivi:
i += 1
non sta facendo quello che pensi che stia facendo. I numeri interi sono immutabili. Questo può essere visto quando guardi cosa è effettivamente l'oggetto in Python:
a = 0
print('ID of the first integer:', id(a))
a += 1
print('ID of the first integer +=1:', id(a))
La funzione id rappresenta un valore unico e costante per un oggetto nella sua vita. Concettualmente, si associa liberamente a un indirizzo di memoria in C / C ++. Esecuzione del codice sopra:
ID of the first integer: 140444342529056
ID of the first integer +=1: 140444342529088
Ciò significa che il primo a
non è più lo stesso del secondo a
, perché i loro ID sono diversi. In effetti si trovano in diverse posizioni nella memoria.
Con un oggetto, tuttavia, le cose funzionano diversamente. Ho sovrascritto l' +=
operatore qui:
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'esecuzione di questo risulta nel seguente output:
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
Si noti che l'attributo id in questo caso è effettivamente lo stesso per entrambe le iterazioni, anche se il valore dell'oggetto è diverso (è possibile trovare anche id
il valore int contenuto nell'oggetto, che cambierebbe mentre sta mutando, perché numeri interi sono immutabili).
Confronta questo con quando esegui lo stesso esercizio con un oggetto immutabile:
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))
Questo produce:
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
Alcune cose qui da notare. Innanzitutto, nel ciclo con il +=
, non si sta più aggiungendo all'oggetto originale. In questo caso, poiché gli ints sono tra i tipi immutabili in Python , python utilizza un ID diverso. È anche interessante notare che Python utilizza lo stesso sottostante id
per più variabili con lo stesso valore immutabile:
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 ha una manciata di tipi immutabili, che causano il comportamento che vedi. Per tutti i tipi mutabili, le tue aspettative sono corrette.
i
è immutabile o se stai eseguendo un'operazione non mutante. Con un elenco nidificatofor i in a: a.append(1)
avrebbe un comportamento diverso; Python non copia gli elenchi nidificati. Tuttavia, i numeri interi sono immutabili e l'aggiunta restituisce un nuovo oggetto, non modifica quello vecchio.