Reputation: 53
I'm learning about classes and don't understand this:
class MyClass:
var = 1
one = MyClass()
two = MyClass()
print(one.var, two.var) # out: 1 1
one.var = 2
print(one.var, two.var) # out: 2 1
I thought that class variables are accessible by all instances, why is the Class variable not updating for all its instances?
Upvotes: 5
Views: 2786
Reputation: 10005
If both Class and Instance (object) have variables/attributes with a same name, accessing such attributes via Instance (object), will always return the variable/attribute from the Instance (object) itself, shadowing the Class variable/attribute: Instance attributes takes precedence over a Class attributes, if they have the same names.
You're setting an instance
variable (attribute) instead of interacting with the class
variable, as it was mentioned on the comments.
class Message: default = "nothing here..."
Message.default
>>> 'nothing here...'
m = Message()
m.default
>>> 'nothing here...'
default
is defined on the instancem.default = "Say your name."
m.default
>>> 'Say your name.'
Message.default = "Anybody there?"
Message.default
'Anybody there?'
default
from m
objectm.default
>>> 'Say your name.'
m.__delattr__("default")
m.default
>>> 'Anybody there?'
Safer ways of accessing Class variables via its instances (I recommend the last one):
type(m).default
>>> 'Anybody there?'
m.__class__.default
>>> 'Anybody there?'
Upvotes: 0
Reputation: 1
In fact, one.var = 2
sets a new instance variable called var
: it doesn't change the class variable var
.
That being said, one.var
accesses a new instance variable, and not the class variable.
If both class and instance have the same variable name, the access to the instance variable, is prioritized, shadowing the class variable when accessing the variable via instance:
class MyClass:
var = 1
one = MyClass()
two = MyClass()
print(one.var, two.var)
one.var = 2 # Adds the new instance variable by object
# ↓ Accesses the class variable by object
print(one.var, two.var)
# ↑
# Accesses the new instance variable by object
Output:
1 1
2 1
To change the class variable var
, you need to use the class itself:
class MyClass:
var = 1
one = MyClass()
two = MyClass()
print(one.var, two.var)
MyClass.var = 2 # Changes the class variable by the class name
print(one.var, two.var)
Output:
1 1
2 2
My answer for a similar topic explains more about accessing class variables.
Upvotes: 2
Reputation: 530920
Assignment to an attribute via an instance always creates/updates an instance variable, whether or not a class attribute of the same name exists. To update a class attribute, you must use a reference to the class.
>>> type(one).var = 2
>>> print(one.var, two.var)
2 2
In practice, type(one)
might return the wrong class to update a particular class attribute, but also in practice, you don't need to change class attributes when you only have an instance of the class available.
Upvotes: 3
Reputation: 880
It doesn't change for all of them because doing this: one.var = 2
, creates a new instance variable
with the same name as the class variable, but only for the instance one
.
After that, one
will first find its instance variable and return that, while two
will only find the class variable and return that.
To change the class variable I suggest two options:
create a class method to change the class variable (my preference)
change it by using the class directly
class MyClass:
var = 1
@classmethod
def change_var(cls, var):
cls.var = var
one = MyClass()
two = MyClass()
print(one.var, two.var) # out: 1 1
one.change_var(2) # option 1
print(one.var, two.var) # out: 2 2
MyClass.var = 3 # option 2
print(one.var, two.var) # out: 3 3
Upvotes: 4