63

What is the difference between class and instance variables in Python?

class Complex:
    a = 1

and

class Complex:
    def __init__(self):
        self.a = 1

Using the call: x = Complex().a in both cases assigns x to 1.

A more in-depth answer about __init__() and self will be appreciated.

martineau
  • 119,623
  • 25
  • 170
  • 301
Christopher Markieta
  • 5,674
  • 10
  • 43
  • 60
  • [In Python how can I access “static” class variables within class methods](http://stackoverflow.com/questions/707380/in-python-how-can-i-access-static-class-variables-within-class-methods) – storm_m2138 Aug 11 '15 at 17:44

2 Answers2

114

When you write a class block, you create class attributes (or class variables). All the names you assign in the class block, including methods you define with def become class attributes.

After a class instance is created, anything with a reference to the instance can create instance attributes on it. Inside methods, the "current" instance is almost always bound to the name self, which is why you are thinking of these as "self variables". Usually in object-oriented design, the code attached to a class is supposed to have control over the attributes of instances of that class, so almost all instance attribute assignment is done inside methods, using the reference to the instance received in the self parameter of the method.

Class attributes are often compared to static variables (or methods) as found in languages like Java, C#, or C++. However, if you want to aim for deeper understanding I would avoid thinking of class attributes as "the same" as static variables. While they are often used for the same purposes, the underlying concept is quite different. More on this in the "advanced" section below the line.

An example!

class SomeClass:
    def __init__(self):
        self.foo = 'I am an instance attribute called foo'
        self.foo_list = []

    bar = 'I am a class attribute called bar'
    bar_list = []

After executing this block, there is a class SomeClass, with 3 class attributes: __init__, bar, and bar_list.

Then we'll create an instance:

instance = SomeClass()

When this happens, SomeClass's __init__ method is executed, receiving the new instance in its self parameter. This method creates two instance attributes: foo and foo_list. Then this instance is assigned into the instance variable, so it's bound to a thing with those two instance attributes: foo and foo_list.

But:

print instance.bar

gives:

I am a class attribute called bar

How did this happen? When we try to retrieve an attribute through the dot syntax, and the attribute doesn't exist, Python goes through a bunch of steps to try and fulfill your request anyway. The next thing it will try is to look at the class attributes of the class of your instance. In this case, it found an attribute bar in SomeClass, so it returned that.

That's also how method calls work by the way. When you call mylist.append(5), for example, mylist doesn't have an attribute named append. But the class of mylist does, and it's bound to a method object. That method object is returned by the mylist.append bit, and then the (5) bit calls the method with the argument 5.

The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store that one string in memory, because they can all find it.

But you have to be a bit careful. Have a look at the following operations:

sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)

sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)

print sc1.foo_list
print sc1.bar_list

print sc2.foo_list
print sc2.bar_list

What do you think this prints?

[1]
[2, 20]
[10]
[2, 20]

This is because each instance has its own copy of foo_list, so they were appended to separately. But all instances share access to the same bar_list. So when we did sc1.bar_list.append(2) it affected sc2, even though sc2 didn't exist yet! And likewise sc2.bar_list.append(20) affected the bar_list retrieved through sc1. This is often not what you want.


Advanced study follows. :)

To really grok Python, coming from traditional statically typed OO-languages like Java and C#, you have to learn to rethink classes a little bit.

In Java, a class isn't really a thing in its own right. When you write a class you're more declaring a bunch of things that all instances of that class have in common. At runtime, there's only instances (and static methods/variables, but those are really just global variables and functions in a namespace associated with a class, nothing to do with OO really). Classes are the way you write down in your source code what the instances will be like at runtime; they only "exist" in your source code, not in the running program.

In Python, a class is nothing special. It's an object just like anything else. So "class attributes" are in fact exactly the same thing as "instance attributes"; in reality there's just "attributes". The only reason for drawing a distinction is that we tend to use objects which are classes differently from objects which are not classes. The underlying machinery is all the same. This is why I say it would be a mistake to think of class attributes as static variables from other languages.

But the thing that really makes Python classes different from Java-style classes is that just like any other object each class is an instance of some class!

In Python, most classes are instances of a builtin class called type. It is this class that controls the common behaviour of classes, and makes all the OO stuff the way it does. The default OO way of having instances of classes that have their own attributes, and have common methods/attributes defined by their class, is just a protocol in Python. You can change most aspects of it if you want. If you've ever heard of using a metaclass, all that is is defining a class that is an instance of a different class than type.

The only really "special" thing about classes (aside from all the builtin machinery to make them work they way they do by default), is the class block syntax, to make it easier for you to create instances of type. This:

class Foo(BaseFoo):
    def __init__(self, foo):
        self.foo = foo

    z = 28

is roughly equivalent to the following:

def __init__(self, foo):
    self.foo = foo

classdict = {'__init__': __init__, 'z': 28 }

Foo = type('Foo', (BaseFoo,), classdict)

And it will arrange for all the contents of classdict to become attributes of the object that gets created.

So then it becomes almost trivial to see that you can access a class attribute by Class.attribute just as easily as i = Class(); i.attribute. Both i and Class are objects, and objects have attributes. This also makes it easy to understand how you can modify a class after it's been created; just assign its attributes the same way you would with any other object!

In fact, instances have no particular special relationship with the class used to create them. The way Python knows which class to search for attributes that aren't found in the instance is by the hidden __class__ attribute. Which you can read to find out what class this is an instance of, just as with any other attribute: c = some_instance.__class__. Now you have a variable c bound to a class, even though it probably doesn't have the same name as the class. You can use this to access class attributes, or even call it to create more instances of it (even though you don't know what class it is!).

And you can even assign to i.__class__ to change what class it is an instance of! If you do this, nothing in particular happens immediately. It's not earth-shattering. All that it means is that when you look up attributes that don't exist in the instance, Python will go look at the new contents of __class__. Since that includes most methods, and methods usually expect the instance they're operating on to be in certain states, this usually results in errors if you do it at random, and it's very confusing, but it can be done. If you're very careful, the thing you store in __class__ doesn't even have to be a class object; all Python's going to do with it is look up attributes under certain circumstances, so all you need is an object that has the right kind of attributes (some caveats aside where Python does get picky about things being classes or instances of a particular class).

That's probably enough for now. Hopefully (if you've even read this far) I haven't confused you too much. Python is neat when you learn how it works. :)

vvv444
  • 2,764
  • 1
  • 14
  • 25
Ben
  • 68,572
  • 20
  • 126
  • 174
  • 2
    My comment (which I took excessively long to write) got ninja'd by the second part of your post! Good work. :) – voithos Jan 22 '12 at 06:19
  • 1
    Best answer I'v read yet! I understood everything except the BaseFoo stuff, have you ever considered writing a book? Although you referenced instances as a lot of things, I think I understand this stuff now and you really gave me what I was asking for. :) – Christopher Markieta Jan 22 '12 at 18:13
  • @ChristopherM Thanks for the compliment! BaseFoo was a base class that Foo was inheriting from, in that example block. That whole "advanced study" section was aimed at readers who are new to Python but familiar with object-oriented techniques and terminology from settings such as Java, C++, etc. If that doesn't include you, then don't worry too much about it, you'll learn about that stuff as you keep learning Python. :) – Ben Jan 23 '12 at 00:17
  • I come from a C background but with little experience and some JavaScript, so far Python is my best subject but I'm starting to learn Java and hopefully C++ sooner or later! Thanks. – Christopher Markieta Jan 23 '12 at 00:34
  • My big thanks for that great answer. Helped me alot understanding the differences in python, seen from C# points of view. – Oliver Friedrich Sep 05 '12 at 10:04
  • If you don't mind, can you update your answer to mention that "class variables" are called "static variables" in other languages? That would help people understand more quickly what you're talking about. – ashes999 Mar 08 '13 at 02:49
  • @ashes999 I've added a mention of static variables, since you're right that that could help people get what I'm talking about. I think it's not quite correct to say that "class attributes" are called "static variables" in other languages though; traditional static OO languages don't really *have* a concept of "class attributes" (because classes are not objects that can have attributes). Would you agree with what I've added? – Ben Apr 10 '13 at 23:18
  • 1
    @Ben For the example with `sc1,sc2`, if I set `sc1.bar = "something else"`, then`sc2.bar` is still `I am a class attribute called bar`. This looks like each instance has its own class variable, which makes class variable not different from the instance variable? If I set `SomeClass.bar='another thing'`, then `sc1.bar = 'something else'` and `sc2.bar='another thing'` – KevinKim Jul 22 '17 at 14:33
  • 1
    @ftxx Assignment does *not* use the lookup protocol. `sc1.bar = ...` writes to the `bar` attribute of `sc1` (creating a new attribute) **not** the `bar` attributes of `SomeClass`. Thereafter when you *read* `sc1.bar` it sees an instance attribute and gives you that value, while reading `sc2.bar` still sees that `sc2` has no attribute `bar` and falls back to the class attribute. The examples with appending to `bar_list` show the difference. Remember that assignment doesn't actually affect the object you would have retrieved from the variable, it just creates or replaces a reference. – Ben Jul 22 '17 at 22:12
  • I realize this anwser is 5 years old, but… the explanation of methods is wrong. "But the class of mylist does, and it's bound to a method object." That's sort of true in Python 2, and not at all true in Python 3. It's bound to an unbound-method object in 2.x, or a plain old function in 3.x. But either way, Python does not return that object to you; it calls `__get__` on that object, and that `__get__` method creates the method object that you see. – abarnert May 12 '18 at 22:37
  • @abarnert It's true, I oversimplified to avoid getting into a digression on the descriptor protocols. – Ben May 13 '18 at 12:03
11

What you're calling an "instance" variable isn't actually an instance variable; it's a class variable. See the language reference about classes.

In your example, the a appears to be an instance variable because it is immutable. It's nature as a class variable can be seen in the case when you assign a mutable object:

>>> class Complex:
>>>    a = []
>>>
>>> b = Complex()
>>> c = Complex()
>>> 
>>> # What do they look like?
>>> b.a
[]
>>> c.a
[]
>>> 
>>> # Change b...
>>> b.a.append('Hello')
>>> b.a
['Hello']
>>> # What does c look like?
>>> c.a
['Hello']

If you used self, then it would be a true instance variable, and thus each instance would have it's own unique a. An object's __init__ function is called when a new instance is created, and self is a reference to that instance.

voithos
  • 68,482
  • 12
  • 101
  • 116
  • 7
    So basically class variables are like static variables in other languages then? – Jeff LaFay Jan 22 '12 at 05:21
  • 1
    @jlafay: Yes, basically. After the code that I gave, you could have checked `Complex.a` (the class, not instance) and noticed that it was `['Hello']`. :D – voithos Jan 22 '12 at 05:23
  • "each instance would have it's own unique `a`.". Can you define more than one `__init__` function in a class? Or do all functions in the class count as instances? – Christopher Markieta Jan 22 '12 at 18:53
  • @ChristopherM: Why would you need multiple `__init__`? The init is the "constructor" of an instance, if you will. If you need to do complicated things, then just separate out the tasks into separate functions and call them from `__init__`. As for your other question, like Ben mentioned, functions of a class aren't actually stored in the instances of the class. When Python does a function lookup, it search the dictionary (`__dict__`) of the instance first, and, having not found the function, goes to search in the class. If found, the function is called with the instance as an argument. – voithos Jan 22 '12 at 20:33
  • Oh my mistake I see what you mean now. But when referring to an "instance variable", does that refer to a variable inside the constructor or the new object? – Christopher Markieta Jan 22 '12 at 22:51
  • 1
    @ChristopherM: It refers to a variable that is assigned to the object. `__init__` behaves just like a normal function, if you look past its special properties. That means that you can use temporary variables in the function's scope, just like in any other function. These aren't preserved in the object, unless you explicitly assign them to `self`, in which case you are simply assigning them to the instance itself. – voithos Jan 23 '12 at 03:51
  • @voithos If in your example, `a` is not a list but just a numerical variable, say with default value 5, then when you create 2 objects, `b,c`and if you change `b.a = 15`, then it has not effect of `c.a`, which is still 5. So in this case, it seems that the class variable is the same as the instance variable (the self.variable)? – KevinKim Jul 22 '17 at 14:43
  • @ftxx: Note quite. You're seeing this because the assignment `b.a = 15` creates a _new instance variable_ on that object (these are more properly called "data attributes" and "class attributes"). When reading `b.a`, Python finds the instance's data attribute first, and returns it without looking at the class. To see how the behavior can differ, notice that if you instead assign to the _class_, `Complex.a = 55`, subsequent reads from instances will return the new value (so `c.a` will give `55`), _unless_ you've created a data attribute with the same name (so `b.a` still gives `15`). – voithos Jul 23 '17 at 00:40
  • This example would be more great if you'd put the example with __self__ as well, so that we can see the difference. – Siyah Nov 07 '17 at 12:00