azertqwert
azertqwert

Reputation: 53

Why is the Class variable not updating for all its instances?

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

Answers (4)

ivanleoncz
ivanleoncz

Reputation: 10005

Accessing Class variables via its Instances, is not ideal

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.


Side Example

  • a Class defined with a variable, accessed via the Class itself
class Message: default = "nothing here..."                                     
Message.default                                                                
>>> 'nothing here...'
  • an instance (object) is created and the Class variable is accessed via instance
m = Message()                                                                  
m.default                                                                      
>>> 'nothing here...'
  • an attribute default is defined on the instance
m.default = "Say your name."                                                   
m.default                                                                      
>>> 'Say your name.'
  • the Class variable is updated
Message.default = "Anybody there?"                                             
Message.default                                                                
'Anybody there?'
  • and nothing happens with the attribute default from m object
m.default                                                                      
>>> 'Say your name.'
  • if the attribute is deleted, then the Class variable is once accessible via instance (object)
m.__delattr__("default")                                                       
m.default                                                                      
>>> 'Anybody there?'

Summing up

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

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

chepner
chepner

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

Stryder
Stryder

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:

  1. create a class method to change the class variable (my preference)

  2. 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

Related Questions