Class Variable Access and Assignment

Steven D'Aprano steve at REMOVETHIScyber.com.au
Fri Nov 4 16:22:04 CET 2005


On Fri, 04 Nov 2005 09:03:56 +0000, Antoon Pardon wrote:

> Op 2005-11-03, Steven D'Aprano schreef <steve at REMOVETHIScyber.com.au>:
>> 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?
> 
> Since AFAICT there is no single reference to the __len__ attribute that
> will be resolved to two different namespace I don't see the relevance.

Compare:

b.a += 2

Before the assignment, instance b does not have an attribute "a", so class
attribute "a" is accessed. You seem to be objecting to this inheritance.

len(L) => L.__len__()

Instance L also does not have an attribute "__len__", so class attribute
"__len__" is accessed. You don't appear to object to this inheritance.

Why object to one and not the other?

If you object to b.a resolving to b.__class__.a, why don't you object to
L.__len__ resolving to L.__class__.__len__ also?

Perhaps you don't object to that half of the problem. Perhaps you object
to the assignment: you expect that assigning to b.a should assign to
b.__class__.a instead.

Should assigning to L[0] assign to L.__class__[0] also, so that all
lists share not only the same behaviour, but also the same data?


[snip]
 
>> 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 some namespaces take great care not to allow a rebinding that would
> result in the same name being resolved to a different namespace during
> this namespace's lifetime.

And some take great care to allow such a rebinding, because that is the
right thing to do to make inheritance work correctly.


>> But b.a is not a name, it is an attribute lookup,
> 
> An other implementation detail. b.a is a name search of 'a' in the
> namespace b.

Factually incorrect. b.a is the name search for 'a' in the namespaces
[note plural] of b, b.__class__, and any superclasses of b, *in that order*.

Do you object to import searching multiple directories?

Why do you object to attribute resolution searching multiple namespaces?


[snip]
>>> 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'
>>
>>
> I don't see the relevance of these pieces of code. In none of them is
> there an occurence of an attribute lookup of the same attribute that
> resolves to different namespaces.

Look a little more closely. In all three pieces of code, you have a
conflict between the class attribute 'ls' and an instance attribute 'ls'.

In the first scenario, that conflict is resolved by insisting that
instances explicitly define an attribute, in other words, by making
instance attribute ONLY search the instance namespace and not the class
namespace.

In the second scenario, that conflict is resolved by insisting that
instance.name assigns to instance.__class__.name, just as you asked for.

The third scenario is the way Python actually operates.



-- 
Steven.




More information about the Python-list mailing list