-1

While learning python through python docs, i came across the following wherein its explained that class variable is common to the class and that any object can change it:

Sample Code 1:

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)

Output:

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks                # unexpectedly shared by all dogs
['roll over', 'play dead']

Question => If so, then why doesn't y in the following example get affected when x changes its tricks attribute to 5?

Sample Code 2:

class Complex:
    tricks = 3
    def __init__(self,var1):
        self.tricks=var1

    def add_tricks(self,var1):
        self.tricks=var1

x = Complex(11)
y = Complex(12)
print (x.tricks)
print (y.tricks)

x.add_tricks(5)
print (x.tricks)
print (y.tricks) -->Remains unchanged

Output:

11
12
5
12 -->Remains unchanged

And what exactly is the difference when i remove the self in the following program:

Sample Code 3:

class Complex:
    tricks = 3
    def __init__(self,var1):
        self.tricks=var1

    def add_tricks(self,var1):
        tricks=var1

x = Complex(11)
y = Complex(12)
print (x.tricks)
print (y.tricks)

x.add_tricks(5) -->This change is not reflected anywhere
print (x.tricks)
print (y.tricks)
print(Complex.tricks)

Output:

11
12
11
12
3
anurag86
  • 1,635
  • 1
  • 16
  • 31
  • 1
    In the first case you are *modifying* a list in the classes namespace that is just accessed via `self`. In the seconds case you are *assigning* a values to `self.tricks` in the namespace of the instance. This will overwrite any earlier value. – Klaus D. Jul 22 '19 at 11:37
  • See first two points of [this answer](https://stackoverflow.com/a/5690920/2201041) –  Jul 22 '19 at 11:39

1 Answers1

2

This example may be illustrative. Given the following class (I've dropped the initialiser from your example because it doesn't let us demonstrate the behaviour):

class Complex:
    tricks = 3
    def add_tricks(self, value):
        self.tricks = value

We can see, upon creation, the value of their tricks attribute is both 3:

>>> a = Complex()
>>> b = Complex()
>>> 
>>> a.tricks
3
>>> b.tricks
3

Let's take a second and look at the names defined on those objects:

>>> a.__dict__
{}
>>> b.__dict__
{}

They're both objects with no attributes themselves. Let's see what happens after we call add_tricks on b:

>>> b.add_tricks(5)
>>>   
>>> a.tricks
3
>>> b.tricks
5

Okay. So, this looks like the shared value hasn't been affected. Let's take a look at their names again:

>>> a.__dict__
{}
>>> b.__dict__
{'tricks': 5}

And there it is. Assigning to self.tricks creates an attribute local to that object with name tricks, which when accessed via the object (or self) is the one that we'll use from that point forward.

The shared value is still there and unchanged:

>>> a.__class__.tricks
3
>>> b.__class__.tricks
3

It's just on the class, not on the object.

Brett Lempereur
  • 815
  • 5
  • 11