2013-06-10 30 views
5

Zauważyłem (pozornie) dziwne zachowanie przy zadaniach, które doprowadziło mnie kilka razy do popełnienia błędów w programowaniu.Reguły przypisywania

Patrz poniższy pierwszy przykład:

>>> i = 0 
>>> t = (i,) 
>>> t 
(0,) 
>>> i += 1 
>>> t 
(0,) 

Zgodnie z oczekiwaniami, wartość unikalnego elementu t nie zmienia się, nawet po wartość i została zwiększona.

Zobacz teraz następujące:

>>> l = [0] 
>>> t = (l,) 
>>> t 
([0],) 
>>> l[0] += 1 
>>> t 
([1],) # <- ? 

Nie rozumiem dlaczego początkowe zera w t jest obecnie jednym; gdybym zwiększany go z odniesieniem do t ...

>>> t[0][0] += 1 

... ja rozumiem, że jest to wartość uległa zmianie, ale nie jest to przypadek w poprzednim przykładzie, gdzie tylko l wyraźnie odwołuje przy inkrementacji.

Mam dwa pytania:

  1. Dlaczego tak jest?
  2. Czy istnieją specjalne zasady, o których powinienem wiedzieć?

Odpowiedz

8

To dlatego, że liczby całkowite są niezmienne, a listy są zmienne.

>>> i = 0 
>>> t = (i,) 
>>> t[0] is i # both of them point to the same immutable object 
True 
>>> i += 1 # We can't modify an immutable object, changing `i` simply 
      # makes it point to a new object 2. 
      # All other references to the original object(0) are still intact. 
>>> i 
1 
>>> t  # t still points to the same 0 
(0,) 
>>> x = y = 1 
>>> id(x),id(y) 
(137793280, 137793280) 
>>> x += 1 
>>> id(x),id(y)  #y still points to the same object 
(137793296, 137793280) 

na listach:

>>> l = [0] 
>>> t = (l,)  
>>> t[0] is l #both t[0] and l point to the same object [0] 
True 
>>> l[0] += 1 # modify [0] in-place 
>>> t 
([1],) 
>>> l 
[1] 
#another exmple 
>>> x = y =[] # x, y point to the same object 
>>> x.append(1) # list.append modifies the list in-place 
>>> x, y   
([1], [1]) 
>>> x = x + [2] # only changes x, x now points to a new object 
>>> x, y 
([1, 2], [1]) 
+0

Należy więc wiedzieć, czy ma do czynienia z obiektami zmiennymi (listami, zestawami itp.) Lub obiektami niezmiennymi (łańcuchy, liczby całkowite, krotki ...)? – michaelmeyer

+0

Istnieje również fakt, że krotki są niezmienne; jeśli obiekt przechowywany w krotce był zmienny, ale nie implementował '__iadd__', operacja nadal nie działałaby; jednak z niestandardową metodą '__iadd__' (która modyfikuje' self'), robi to. – JAB

+0

@doukremt Możesz modyfikować zmienny obiekt z dowolnego z jego odwołań (tylko operacje w miejscu, 'append',' extend', '+ ='), podczas gdy modyfikowanie obiektu niezmiennego zawsze zwraca nowy obiekt i wszystkie inne odwołania nadal wskaż stary obiekt. –

2

W drugim przykładzie t (krotka) posiada odniesienie do l (listy). Kiedy robisz l[0] += 1, zmieniasz listę, ale krotka nadal zawiera odniesienie do listy. W pierwszym przykładzie, gdy robisz i += 1, faktycznie tworzysz nową liczbę całkowitą, której krotka nie zawiera odniesienia. Zobacz, this answer, którą napisałem chwilę, aby uzyskać bardziej szczegółowe wyjaśnienie operatora += i jak jest on faktycznie zaimplementowany.

+0

Duży +1 za wyjaśnienie różnicy między '+ =' i '= ... +' – michaelmeyer