Python Class Instance Variables and Class Variables

Instance variables vs. class variables in Python

If you have only one instance anyway, it's best to make all variables per-instance, simply because they will be accessed (a little bit) faster (one less level of "lookup" due to the "inheritance" from class to instance), and there are no downsides to weigh against this small advantage.

Why have a class with both a class variable and an instance variable of the same name?

In Python that can be used for defaults.... for example:

class Foo:
x = 1

a = Foo()
b = Foo()
print(a.x, b.x) # --> 1 1
a.x = 2
print(a.x, b.x) # --> 2 1

python class instance variables and class variables

This is because of the way Python resolves names with the .. When you write self.list the Python runtime tries to resolve the list name first by looking for it in the instance object, and if it is not found there, then in the class instance.

Let's look into it step by step

self.list.append(1)
  1. Is there a list name into the object self?

    • Yes: Use it! Finish.
    • No: Go to 2.
  2. Is there a list name into the class instance of object self?

    • Yes: Use it! Finish
    • No: Error!

But when you bind a name things are different:

self.list = []
  1. Is there a list name into the object self?

    • Yes: Overwrite it!
    • No: Bind it!

So, that is always an instance variable.

Your first example creates a list into the class instance, as this is the active scope at the time (no self anywhere). But your second example creates a list explicitly in the scope of self.

More interesting would be the example:

class testClass():
list = ['foo']
def __init__(self):
self.list = []
self.list.append('thing')

x = testClass()
print x.list
print testClass.list
del x.list
print x.list

That will print:

['thing']
['foo']
['foo']

The moment you delete the instance name the class name is visible through the self reference.

Can python class variables become instance variables when altered in __init__?

That would be the solution indeed, but is that still an instance variable? Because it is defined in the class body, it would be a class variable in my understanding. [...snip...] However, it seems wrong to me if you call it an instance variable and I don't know if I should use it like this just to have the type hinting working.

For what it's worth, I also share the same discomfort. It seems like we're conceptually mixing two concepts there just for the sake of having cleaner type annotations.

However, I've asked Guido one or two times about this, and it seems like he does indeed prefers treating those class attributes as if they were instance attributes.

In any case, to answer your core question, if we do this:

class Test:
field1: int
field2: str = 'foo'

Then...

  1. PEP 484 and 526 compliant type checkers will treat this class as if:

    1. It has an instance attribute named field1
    2. It has an instance attribute named field2 that has a default value of 'foo' (as per PEP 526).
  2. At runtime, ignoring type hints, Python will:

    1. Add a class annotation named field1 to Test, but not a class attribute. (Class annotations are not automatically turned into class attributes.)
    2. Add both a class annotation named field2 to Test as well as a class attribute named field2 containing the value 'foo'.

So, it can get a bit muddled.

But regardless, this then begs the question: how do we indicate to a type checker that we want some field to genuinely be a class attribute?

Well, it turns out PEP 484 was amended semi-recently to contain the ClassVar type annotation, which does exactly that.

So, if we wanted to add a new class attribute, we could do this:

from typing import ClassVar

class Test:
field1: int
field2: str = 'foo'
field3: ClassVar[int] = 3

So now, field3 should be treated as a class attribute with a default value of '3'.

(Note: ClassVar was added to typing for Python 3.5.3 -- if you're using the older version of typing bundled with Python 3.5, you can get a "backport" of the type by installing the typing_extensions third part module via pip and importing ClassVar from there instead.)

I think whether you decide to embrace this approach or not use it is a personal preference.

On one hand, Guido's opinion, pretty much by definition, defines what's "Pythonic" or not, so from that stance, there's no issue adopting this new idiom. Furthermore, the language itself is slowly but surely shifting to adopt this new idiom -- see the very recently accepted PEP 557, for example, which ends up following this same idiom of treating class attributes/class annotations as instance attributes.

On the other hand, it's difficult to shake off the nagging worry that this subtle difference will lead to issues down the line. In that case, you could stick with the standard approach of just setting all your fields inside __init__. This approach also has the benefit of keeping your code compatible with Python 2 and 3.x - 3.5.

A middle ground might be to just simply never use class attributes, in any way, shape, or form, and just stick to using class annotations. This is slightly restrictive, since we can no longer give our instance variables default values, but we can now avoid conflating class attributes with instance attributes entirely. (As previously stated, and as pointed out in the comments, class annotations are not added as class attributes.)

In Python, do objects have their own copies of class variables?

It's a bit more complex than that. There are both class variables and instance variables, but what's happening in your example is that the class variable is being overridden by the instance variable.

Consider the following:

>>> class Foobar:
... my_list = []
...
>>> foo = Foobar()
>>> Foobar.my_list.append('hello')
>>> foo.my_list.append('world')
>>> foo.my_list
['hello', 'world']

As you can see the Foobar class and foo instance share a variable here. So no, instantiating a class does not "copy" all the class variables. Consider this, however:

>>> foo.my_list = ['spam', 'eggs']
>>> foo.my_list
['spam', 'eggs']
>>> Foobar.my_list
['hello', 'world']

Now we have two variables, one that's a class variable, the other that's an instance variable. They are no longer the same.

If you wanted to always use class variables, the most elegant thing would be to use class methods. Eg,

class Human:

population = 0

# initialization.
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

@classmethod
def increment_pop(cls):
cls.population += 1

Now because increment_pop is a class method, it will always operate on the class, not the instance. However, the population attribute will be available to instances and as long as they don't overwrite it, it will be the same as the class variable.

A few important things to keep in mind:

  1. Primitives, like integers and strings, are immutable. When you do foo += 1, you're creating a new instance of an integer and replacing the old one. You're not modifying it in place.

  2. Instances can access class variables and class methods with self.whatnot. But if you want to be unambiguous, you can also reference them as ClassName.whatnot.

  3. Class methods can be called from instances, similarly, like self.class_method().

Other notes on Python variables

Let's back up here and consider how Python resolves a request for something like my_human.population on the instance:

  1. First, Python looks for an instance attribute named population. If it exists, that's the value you get.
  2. Second, Python looks for a class attribute named population. If that exists, that's the value you get.

So, when you have no assigned population on your instance, and you access self.population, since no instance attribute exists with that name, you get the class attribute.

However, once you assign an instance attribute to your object, that second step above never happens.

You can inspect this at runtime, too:

>>> class Human:
... population = 0
...
>>> my_human = Human()
>>> 'population' in Human.__dict__
True
>>> 'population' in my_human.__dict__
False

So population only exists on the Human class, not on the instance. When we access Human.population, it finds the class attribute:

>>> my_human.population
0

But what happens if I create an instance attribute?

>>> Human.population = 100
>>> my_human.population = 50
>>> Human.population
100
>>> my_human.population
50

Now, because the instance has an attribute matching the name population, when you access my_human.population, it never looks up what's on the class.

Difference between Class variables and Instance variables

Class variables are shadowed by instance attribute. This means that when looking up an attribute, Python first looks in the instance, then in the class. Furthermore, setting a variable on an object (e.g. self) always creates an instance variable - it never changes the class variable.

This means that when, in your second example you do:

self.x += 1

which is (in this case, see footnote) equivalent to:

self.x = self.x + 1

what Python does is:

  1. Look up self.x. At that point, self doesn't have the instance attribute x, so the class attribute A.x is found, with the value 10.
  2. The RHS is evaluated, giving the result 11.
  3. This result is assigned to a new instance attribute x of self.

So below that, when you look up x.x, you get this new instance attribute that was created in add(). When looking up y.x, you still get the class attribute. To change the class attribute, you'd have to use A.x += 1 explicitly – the lookup only happens when reading the value of an attribute.


Your first example is a classical gotcha and the reason you shouldn't use class attributes as "default" values for instance attributes. When you call:

self.x.append(1)

there is no assignment to self.x taking place. (Changing the contents of a mutable object, like a list, is not the same as assignment.) Thus, no new instance attribute is added to x that would shadow it, and looking up x.x and y.x later on gives you the same list from the class attribute.


Note: In Python, x += y is not always equivalent to x = x + y. Python allows you to override the in-place operators separately from the normal ones for a type. This mostly makes sense for mutable objects, where the in-place version will directly change the contents without a reassignment of the LHS of the expression. However, immutable objects (such as numbers in your second example) do not override in-place operators. In that case, the statement does get evaluated as a regular addition and a reassignment, explaining the behaviour you see.

(I lifted the above from this SO answer, see there for more details.)



Related Topics



Leave a reply



Submit