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:
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.
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.
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:
- First, Python looks for an instance attribute named
population. If it exists, that's the value you get.
- 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.