On 5/15/19 10:52 AM, Irv Kalb wrote:
I just saw some code that confused me.  The confusion has to do with class 
variables and instance variables.  In order to understand it better, I built 
this very small example:


class Test:
     x = 0

     def __init__(self, id):
         self.id = id
         self.show()

     def show(self):
         print('ID:', self.id, 'self.x is:', self.x)

     def increment(self):
         self.x = self.x + 1


# Create two instances of the Test object, each shows itself
t1 = Test('first')
t2 = Test('second')

# Ask t1 to increment itself twice
t1.increment()
t1.increment()

# Ask each to show themselves
t1.show()
t2.show()

# Let's see what the class has
print('Test.x is:', Test.x)


When I instantiate two objects (t1 and t2), the __init__ method calls the show 
method, which prints a value of self.x.  I'm not understanding why this is 
legal.  I would expect that I would get an error message saying that self.x 
does not exist, since no instance variable named self.x has been defined.

However, this code runs fine, and gives the following output:

ID: first self.x is: 0
ID: second self.x is: 0
ID: first self.x is: 2
ID: second self.x is: 0
Test.x is: 0

My guess is that there is some scoping rule that says that if there is no 
instance variable by a given name, then see if there is one in the class.  If 
that is the case, then this line in the increment method seems odd:

self.x = self.x + 1

If the self.x on the right hand side refers to the class variable, and creates 
an instance variable called self.x on the left hand side, then how does the 
second call work using the value of the instance variable on the right hand 
side?  Can someone explain what's going on here?


Pretty much exactly like that. The first time you call t1.increment, you fail to find x in the instance dictionary, fall back and find it equal to 0, add 1 makes 1, and store x=1 into the instance dictionary.

The second time, you find x=1 in the instance dictionary, add 1 makes 2, and overwrite x=2 into the instance dictionary.

You never call increment on t2, so it never gets an x in its instance dictionary, so t2.x still refers to Test.x.

Disclaimer:  I would never write code like this, but I saw this in someone 
else's code and didn't understand how it was working.


Sometimes when I'm feeling lazy it's a convenient way to set defaults on instance variables. I don't love it, but I also can't explain what I find wrong with it.

Irv



--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to