Static variable vs Class variable

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Sat Oct 6 08:28:12 CEST 2007


minkoo.seo at gmail.com a écrit :
> Hi.
> 
> I've got a question on the differences and how to define static and
> class variables.

What's a "static" variable ? A variable that doesn't move ?-)

  > Hence, my understanding is that static variables must be bound to the
> class defining the variables 

You mean "class attributes". Thinking in terms of another language won't 
help understanding Python's objec model.

> and shared by children of parent class
> where the variable is defined. But, please have a look at this code in
> which a guy told me that the variable a is static:

Then don't listen what this guy says.

>>>>class Foo:
> 
> 	a = 1
> 	@classmethod
> 	def increment(cls):
> 		cls.a += 1
> 		print cls.a
> 
> Here, I am defining variable a which, I believe is class variable,

a class attribute

> i.e., variable that is not bound to Foo itself.

Yes it is. It's an attribute of the class object Foo.

> Rather, a is bound to
> the class which is accessing the variable.

False.
 >>> dir(Foo)
['__doc__', '__module__', 'a', 'increment']
 >>> Foo.__dict__
{'a': 1, '__module__': '__main__', '__doc__': None, 'increment': 
<classmethod object at 0x402d141c>}

> The code that corroborates
> this idea is as follows:
> 
>>>>class Child1(Foo):
> 	pass
> 
>>>>Child1.increment()
> 4

???

> 
>>>>class Child2(Foo):
> 	pass
> 
>>>>Child2.increment() 
> 4

I don't have the same result here. But anyway: the increment method is 
rebinding 'a', so the first time it's called on a child class, it 
creates an attribute 'a' for this class. Just change your code this way 
and you'll see what happens:

   def increment(cls):
      print dir(cls)
      cls.a += 1
      print dir(cls)


FWIW, if you don't get this, then you may encounter another common gotcha:

class Truc:
    a = 1
    def gotcha(self):
      self.a += 1
      print self.a

print Truc.a
t = Truc()
print t.a
t.gotcha()
print Truc.a
t2 = Truc()
print t2.a
t2.gotcha()
print Truc.a
t.gotcha()
print t.a
print t2.a
print Truc.a

Enjoy !-)

Now back to your snippet : if you don't want this behaviour, wrap 'a' 
into a mutable container:

class Foo:
     a = [1]

     @classmethod
     def increment(cls):
         cls.a[0] += 1
         print cls.a[0]


class Child(Foo):
     pass

And if you want to hide that, use properties (warning: you need nex 
style classes here):

class Foo(object):
     _a = [1]

     @classmethod
     def increment(cls):
         cls._a[0] += 1
         print cls._a[0]

     @apply
     def a():
         def fget(self):
             return type(self)._a[0]
         def fset(self, val):
             type(self)._a[0] = val
         return property(**locals())

class Child(Foo):
     pass

> This means that Child1 and Child2 does not share variable a which
> means that variable a is class variable rather than static variable.

Nope. This only means that you don't understand the (somewhat peculiar) 
semantics of bindings, immutable objects and attribute lookup rules in 
Python.

> Could you please comment on this? Is a static or class variable?

It's a class attribute.

> What's the most recent way of defining 'class' and 'static' variables?

No 'static variable' in Python. And what you call a 'class variable' is 
nothing else than an ordinary of the class object



More information about the Python-list mailing list