Class Variable Access and Assignment

Steve Holden steve at holdenweb.com
Thu Nov 3 23:41:06 EST 2005


Antoon Pardon wrote:
> Op 2005-11-03, Stefan Arentz schreef <stefan.arentz at gmail.com>:
> 
>>Antoon Pardon <apardon at forel.vub.ac.be> writes:
>>
>>...
>>
>>
>>>>>No matter wat the OO model is, I don't think the following code
>>>>>exhibits sane behaviour:
>>>>>
>>>>>class A:
>>>>>  a = 1
>>>>>
>>>>>b = A()
>>>>>b.a += 2
>>>>>print b.a
>>>>>print A.a
>>>>>
>>>>>Which results in
>>>>>
>>>>>3
>>>>>1
>>>>
>>>>I find it confusing at first, but I do understand what happens :-)
>>>
>>>I understand what happens too, that doesn't make it sane behaviour.
>>>
>>>
>>>>But really, what should be done different here?
>>>
>>>I don't care what should be different. But a line with only one
>>>referent to an object in it, shouldn't be referring to two different
>>>objects.
>>
>>It doesn't.
> 
> 
> Yes it does. If the b.a refers to the instance variable, then an
> AttributeError should be raised, because the instance variable doesn't
> exist yet, so you can't add two to it.
> 
Excuse me. The statement

     a += 2

causes a to refer to a different object after the assignment than it did 
before. So does the statement

     self.a += 2

So why are you so concerned that the pre-assignment reference comes from 
a different scope to the post-assignment reference? The fact remains 
that after both assignments the rebound name can no longer (ever) be 
used to refer to its former referent without a further rebinding taking 
place.

> If the b.a refers to the class variable then two should be added to it.
> 
Wring, wring, wring. (Sorry, got that wrong :-)

> Neither happens instead we get some hybrid in which an instance varible
> is created that gets the value of class variable incrented by two.
> 
Yes. So does this mean you also have a problem with

     def f(x):
         x += 2

     g = 3
     print f(g)

When the function call executes, the name x is bound to an object in the 
call's containing scope. Is it then your contention that the augmented 
assignment in the function should add two to that object, changing the 
value of g?

For extra marks please explain the difference between augmented 
assignment to a function argument and augmented assignment to a class 
variable referenced through self.
> 
>>>In the line: b.a += 2, the b.a should be refering to the class variable
>>>or the object variable but not both. So either it could raise an
>>>attribute error or add two to the class variable.
>>
I'm not sure where this moral imperative comes from, and your arguments 
singularly fail to convince me.

>>It does exactly what you say. It adds 2 to the a *instance variable* of
>>the object instance in 'b'.
> 
> 
> There is no instance variable at that point. How can it add 2, to
> something that doesn't exist at the moment.
> 
It doesn't, it simply proceeds along the lines of all Python assignments 
and resolves the name as a reference to a specific object. It then 
computes a new value from the referenced object and the augmented 
assignment operator's right operand, and rebinds the name to the 
newly-computed value.

Please stop talking about variables.

Although augmented assignment operators have the *option* of updating 
objects in place, surely not even you can require that they do so when 
they are bound to an immutable object such as an integer.
> 
>>It doesn't touch the *class variable* A.a which is still 1.
> 
Why "should" it? Why, why, why? And gain, just for good measure, why? 
Augmented assignment to a function argument doesn't modify the passed 
object when immutable, and you have no problem with that (I know as I 
write that this is just asking for trouble, and it will turn out that 
you also find that behavior deeply controversial ...)

> 
> But it accesses the class variable.
> 
Repeat after me: "Python assignment binds values to names".

When I write

     class something:
         a = 1
         def __init__(self, val=None):
             if val:
                 self.a += val

then in the last statement the augmented assignment rebinds "self.a" 
from the class "variable" to a newly-created instance "variable". I am 
of course using the word "variable" here in a Pythonic sense, rather 
than in the sense that, say, a C programmer would use. In Python I 
prefer to talk about binding names because talking of variables leads 
people to expect that a name is bound to an area of memory whose value 
is modified by assignment, but this is in fact not so.

The initial access to self.a uses the defined name resolution order to 
locate a value that was bound to the name "a" in class scope. So what? 
This is a long-documented fact of Python life. It's *supposed* to be 
that way, dammit.

I fail to understand why this is such a problem for you. But then it's 
clear from long past experience that our perceptions of Python's 
execution model differ quite radically, and that I seem to find it quite 
satisfactory overall, whereas you are forever banging on about what 
"should" be true of Python and what Python "should" do. Which, as is 
probably obvious by now, I sometimes find just a teeny bit irritating. 
Kindly pardon my tetchiness.

I suppose ultimately I'm just more pragmatic than you. Plus I started 
using Icon, whose assignment semantics are very similar, back in the 
1970's, so Python's way of doing things fits my brain quite nicely, 
thank you.

regards
  Steve

PS As a total non-sequitur added for light relief at the end of what 
seems even to me to be a slightly tedious post, I discover I managed to 
misspell "assignment" in four distinct ways during the composition of 
the above.
-- 
Steve Holden       +44 150 684 7255  +1 800 494 3119
Holden Web LLC                     www.holdenweb.com
PyCon TX 2006                  www.python.org/pycon/




More information about the Python-list mailing list