Class Variable Access and Assignment

Steven D'Aprano steve at REMOVETHIScyber.com.au
Thu Nov 3 10:36:41 EST 2005


On Thu, 03 Nov 2005 13:01:40 +0000, Antoon Pardon wrote:

>> Seems perfectly sane to me. 
>>
>> What would you expect to get if you wrote b.a = b.a + 2?
> 
> I would expect a result consistent with the fact that both times
> b.a would refer to the same object.

class RedList(list):
    colour = "red"

L = RedList(())

What behaviour would you expect from len(L), given that L doesn't have a
__len__ attribute?


>> Why do you expect
>> b.a += 2 to give a different result?
> 
> I didn't know I did.

It seems to me that you do.

You didn't appear to be objecting to a line like x = b.a assigning the
value of 1 to x (although perhaps you do). If that was the case, then it
is perfectly reasonable to expect b.a = x + 2 to store 3 into b.a, while
leaving b.__class__.a untouched.

Of course, if you object to inheritance, then you will object to x = b.a
as well.


>> Since ints are immutable objects, you shouldn't expect the value of b.a
>> to be modified in place, and so there is an assignment to b.a, not A.a.
> 
> You are now talking implementation details. I don't care about whatever
> explanation you give in terms of implementation details. I don't think
> it is sane that in a language multiple occurence of something like b.a
> in the same line can refer to different objects

That's an implementation detail only in the sense that "while condition"
is a loop is an implementation detail. It is a *design* detail.

b is a name, and any reference to b (in the same namespace) will refer
to the same object. At least until you rebind it to another object.

But b.a is not a name, it is an attribute lookup, and by Python's rules of
inheritance that lookup will look up attributes in the instance, the
class, and finally any superclasses.

If you persist in thinking of b.a as a name referring to a single object,
of course you will be confused by the behaviour. But that's not what
attribute lookup does.

On the right hand side of an assignment, it will return the first existing
of b.__dict__['a'] or b.__class__.__dict__['a']. On the left hand of an
assignment, it will store into b.__dict__['a'].


> I think it even less sane, if the same occurce of b.a refers to two
> different objects, like in b.a += 2

Then it seems to me you have some serious design problems. Which would you
prefer to happen?


# Scenario 1
# imaginary pseudo-Python code with no inheritance:
class Paragraph:
    ls = '\n'  # line separator

para = Paragraph()
para.ls

=> AttributeError - instance has no attribute 'ls'



# Scenario 2
# imaginary pseudo-Python code with special inheritance:
class Paragraph:
    ls = '\n'  # line separator

linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r'  # magically assigns to the class attribute
linux_para.ls

=> prints '\n\r'


# Scenario 3
# Python code with standard inheritance:
class Paragraph:
    ls = '\n'  # line separator

linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r'
linux_para.ls

=> prints '\n'



-- 
Steven.




More information about the Python-list mailing list