YoavKlein
YoavKlein

Reputation: 2705

Changing a class variable through object Python

The docs give the following example:

class Dog:
    tricks = []             # mistaken use of a class variable
    def __init__(self, name):
        self.name = name
    def add_trick(self, trick):
        self.tricks.append(trick)

d1 = Dog('Fiddo')
d2 = Dog('Buddy')

d1.add_trick("role over")
d2.add_trick("play dead")

print(d2.tricks)
["role over", "play dead"]

This demonstrate a bad usage of class variables, since we obviously don't want the same list of tricks for all our dogs.

But when I try this:

class A:
    static_attr = 'Static'
    def __init__(self):
        self.object_attr = 'Objective'
    
    def change_static(self, val):
        self.static_attr = val
        
a1, a2 = A(), A()
a1.change_static("Something")
print(a2.static_attr)

I get:

Static

Why could be the reason that for a list object, when modifying the class variable through an object it is modified for all instances, but with a string it doesnt?

Upvotes: 0

Views: 45

Answers (2)

Mark
Mark

Reputation: 92440

In the first case you tried to access a variable named self.tricks. Python couldn't find that on the instance to it looked for it on the class and found it. Then you manipulated the value that variable points to by appending to the list.

In the second example you create a name called self.static_attr on the instance with self.static_attr = val and assigned a value to it. Now you have two static_attr variables -- one on the class and one on the instance. This is called shadowing.

Now when you try to access self.static_attr and instance that has not defined it on the instance will get the class variable, but instances that have defined it, will get the instance variable. This is described pretty well in the Classes Documentation

Note, you can still refer to the class variable explicitly with something like:

self.__class__.static_attr

or

A.static_attr

Upvotes: 1

L Maxime
L Maxime

Reputation: 124

Here is something to understand it a little better :

class A:
    static_attr = 'Static'
    def __init__(self):
        self.object_attr = 'Objective'
    
    @staticmethod
    def change_static(val):
        A.static_attr = val
        
a1, a2 = A(), A()
A.change_static("Something")
print(a2.static_attr)

A static attribute is common to every instance of the same class. Hence calling this parameter through the object and not the class may be the problem.

Upvotes: 2

Related Questions