2013-05-29 17 views
6

Grałem z klasami Python i dotarłem do następującego przykładu, w którym dwie zmienne, które wydają się statycznymi zmiennymi klasy, mają inne zachowanie po modyfikacji.Python class variable int vs array

Co tu się dzieje? Moim pierwszym instynktem jest to, że coś trudnego dzieje się z referencjami.

class Foo: 
    a = [] 
    n = 0 
    def bar(self): 
      self.a.append('foo') 
      self.n += 1 

x = Foo() 
print x.a, x.n ([] 0) 
x.bar() 
print x.a, x.n (['foo', 1]) 
y = Foo() 
print y.a, y.n (['foo', 0]) 
y.bar() 
print y.a, y.n (['foo', 'foo'], 1) 
+1

Oto podobny przypadek, na który warto zwrócić uwagę w pythonie http://stackoverflow.com/questions/101268/hidden-features-of-python#113198 – qwwqwwq

Odpowiedz

5

Masz rację - w przypadku Foo.a dostępu self.a faktycznie dostęp Foo.a, która jest dzielona pomiędzy wszystkich wystąpień Foo. Jednak po aktualizacji self.n z += rzeczywiście stworzyć zmienną instancji poziomu na self że cienie Foo.n:

>>> import dis 
>>> dis.dis(Foo.bar) 
    5   0 LOAD_FAST    0 (self) 
       3 LOAD_ATTR    0 (a) 
       6 LOAD_ATTR    1 (append) 
       9 LOAD_CONST    1 ('foo') 
      12 CALL_FUNCTION   1 
      15 POP_TOP    

    6   16 LOAD_FAST    0 (self) 
      19 DUP_TOP    
      20 LOAD_ATTR    2 (n) 
      23 LOAD_CONST    2 (1) 
      26 INPLACE_ADD   
      27 ROT_TWO    
      28 STORE_ATTR    2 (n) 
      31 LOAD_CONST    0 (None) 
      34 RETURN_VALUE  

Innymi słowy, kiedy robisz self.a.append('some value') interpreter pobiera a z pamięci za pomocą nazwy na Foo a następnie mutuje listę, na którą wskazuje Foo.a.

Z drugiej strony, kiedy robisz self.n += 1 tłumacza:

  • pobiera n z Foo (ponieważ nie może znaleźć n na self)
  • Tworzy nową wartość n + 1
  • Przechowuje nowa wartość w atrybucie n na self
+0

Gotcha. Przypis, który powoduje, że cień był (dla mnie) został zaciemniony za '+ ='. Dzięki! – mcamac