35

I started coding in python a week ago, it is my mistake i started coding using oops,classes and objects that soon. I assumed my C++ proficiency will help.... I got bit by the following code

class A:
     var=0
     list=[]
     def __init__(self):
            pass

Here to my surprise, var and list are kinda global variable, it is shared across all instances it seems.... What I thought was it was different across all the instances..... It took me half a day to figure out that.... It does not make even slightest sense, that a variable can be accessed by a class object only, but is shared across all instances....... Just Curious, is there a reason behind it?????

Ken White
  • 123,280
  • 14
  • 225
  • 444
howtechstuffworks
  • 1,824
  • 4
  • 29
  • 46
  • I dont have a problem with class variable not belonging to the class.... but why would all variables outside are static, wihtout the keyword static....... that's against natural instinct.... – howtechstuffworks Jun 14 '12 at 20:01
  • 2
    @howtechstuffworks All languages have different syntax, it's just something you need to get used to. Due to Python's dynamic nature, it's reasonable to bind a variable to the thing it's inside (in this case, the class, not an instance of the class). – Brendan Long Jun 14 '12 at 20:05

4 Answers4

36

var should definitely not be shared as long as you access it by instance.var or self.var. With the list however, what your statement does is when the class gets evaluated, one list instance is created and bound to the class dict, hence all instances will have the same list. Whenever you set instance.list = somethingelse resp. self.list = somethingelse, it should get an instance level value.

Example time:

>>> class A():
...     var = 0
...     list = []
...
>>> a = A()
>>> b = A()
>>> a.var
0
>>> a.list
[]
>>> b.var
0
>>> b.list
[]
>>> a.var = 1
>>> b.var
0
>>> a.list.append('hello')
>>> b.list
['hello']
>>> b.list = ['newlist']
>>> a.list
['hello']
>>> b.list
['newlist']
mensi
  • 9,580
  • 2
  • 34
  • 43
  • 6
    The exact same thing is happening with `var` as with `list`, the difference is that you can't append to `var` like you can with `list`, you can only declare another variable with the same name. – Brendan Long Jun 14 '12 at 20:52
  • @BrendanLong immutable types are different in this situation, since it does not matter if you share them – mensi Jun 14 '12 at 21:46
  • 12
    Yes, I just want to clarify that you *are* sharing the immutable `var`, you're just *also* replacing it with something else whenever you do `self.var = ...`. So the behavior is exactly the same for `var` and `list`, it's just that `list` is more interesting as a shared variable (since it's mutable). – Brendan Long Jun 14 '12 at 21:49
  • This behavior of mutable default arguments is also discussed here: https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments – Gertjan Franken Jul 10 '20 at 16:25
17

These are basically like static variables in Java:

// Example equivalent Java
class A {
    static int var = 0;
    static String[] list;
}

This is the intended behavior: Class variables are for the class.

For normal instance variables, declare them in the constructor:

class A:
    def __init__(self):
        self.var = 0
        self.list = []

You may want to look at Static class variables in Python.

Community
  • 1
  • 1
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • okay, now I tried an exmaple and pretty sure, the list is shared across all.... How about the variable? it is not shared across all instances(I tested it)..... is it still static, do I need to learn anymore before proceeding back to the code.... Thanks for your help....... – howtechstuffworks Jun 14 '12 at 20:39
  • 3
    @howtechstuffworks The other variable is static too, but if you do `self.var="something else"`, then you're setting up an instance variable with the same name (you will have both `A.var` and `self.var`), and it will assume that you mean the instance variable. You can still access the class variable with `A.var`. You can do the same thing with the `list` by declaring an instance method with the same name (`self.list = "something else"`). – Brendan Long Jun 14 '12 at 20:50
  • Yeah actually I moved everything under '__init__()', just another question, I have some variables that needs to be common and not writable..... think like a macro in C or const in C++, where should I write it here???? – howtechstuffworks Jun 14 '12 at 20:53
  • 2
    @howtechstuffworks You should generally open a new thread for each question, but to answer -- Python doesn't have constants. There are some hacks to create them, but the general solution is to name constants in upper case and assume users of your API aren't stupid enough to change them (you'll find this is a common theme in Python -- you can do anything, but just because you can doesn't mean you should). – Brendan Long Jun 14 '12 at 21:02
6

The reason is that in Python class is an executable statement that is executed like any other. The body of the class definition is executed once, when the class is defined. If you have a line line var = [] in there, then it is only executed once, so only one list can ever be created as a result of that line.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
3

Note that you do not see this behaviour for var, you only see it for list:

>>> class A:
...     var = 0
...     list = []
... 
>>> a1 = A()
>>> a2 = A()
>>> a1.var = 3
>>> a2.var
0
Simeon Visser
  • 118,920
  • 18
  • 185
  • 180