> On May 15, 2019, at 11:02 AM, Rob Gaddi <rgaddi@highlandtechnology.invalid> 
> wrote:
> 
> 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
>>                  
> 

Thanks for the confirmation.   I still think its weird to have:

   self.x = self.x + 1

and have it refer to two potentially different variables at different times, 
but at least I understand what's going on.

Irv

-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to