Class Variable Access and Assignment
Bengt Richter
bokr at oz.net
Sun Nov 6 03:40:00 EST 2005
On Sun, 06 Nov 2005 15:17:18 +1100, Steven D'Aprano <steve at REMOVETHIScyber.com.au> wrote:
>On Sat, 05 Nov 2005 18:14:03 -0800, Paul Rubin wrote:
>
>>> instance.attribute sometimes reading from the class attribute is a feature
>>> of inheritance; instance.attribute always writing to the instance is a
>>> feature of OOP; instance.attribute sometimes writing to the instance and
>>> sometimes writing to the class would be, in my opinion, not just a wart
>>> but a full-blown misfeature.
>>
>> But that is what you're advocating: x.y+=1 writes to the instance or
>> the class depending on whether x.y is mutable or not.
>
>Scenario 1:
>
>Pre-conditions: class.a exists; instance.a exists.
>Post-conditions: class.a unchanged; instance.a modified.
>
>I give that a big thumbs up, expected and proper behaviour.
>
>Scenario 2:
>
>Pre-conditions: class.a exists and is immutable; instance.a does not
>exist.
>Post-conditions: class.a unchanged; instance.a exists.
>
>Again, expected and proper behaviour.
>
>(Note: this is the scenario that Antoon's proposed behaviour would change
>to class.a modified; instance.a does not exist.)
>
>Scenario 3:
>
>Pre-conditions: class.a exists and is mutable; instance.a exists.
>Post-conditions: class.a unchanged; instance.a is modified.
>
>Again, expected and proper behaviour.
>
>Scenario 4:
>
>Pre-conditions: class.a exists and is mutable; instance.a does
>not exist.
>Post-conditions: class.a modified; instance.a does not exist.
>
Are you saying the above is what happens or what should happen or not happen?
It's not what happens. Post-conditions are that class.a is modified AND
instance.a gets a _separate_ reference to the same result. Note:
Python 2.4b1 (#56, Nov 3 2004, 01:47:27)
[GCC 3.2.3 (mingw special 20030504-1)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
... a = []
...
>>> b=A()
>>> id(A.__dict__['a'])
49230700
>>> b.a += [123]
>>> id(A.__dict__['a'])
49230700
>>> id(b.__dict__['a'])
49230700
>>> (b.__dict__['a'])
[123]
>>> (A.__dict__['a'])
[123]
Let's eliminate the inheritable class variable A.a:
>>> del A.a
>>> b.a
[123]
>>> id(b.__dict__['a'])
49230700
>>> vars(b)
{'a': [123]}
Make sure we did eliminate A.a
>>> vars(A)
<dictproxy object at 0x02E817AC>
>>> vars(A).keys()
['__dict__', '__module__', '__weakref__', '__doc__']
Is that the "wart" you were thinking of, or are you actually happier? ;-)
>Well, that is a wart. It is the same wart, and for the same reasons, as
>the behaviour of:
>
>def function(value=[]):
> value.append(None)
IMO that's not a wart at all, that's a direct design decision, and it's
different from the dual referencing that happens in Scenario 4.
>
>I can live with that. It is a familiar wart, and keeps inheritance of
>attributes working the right way. And who knows? If your attributes are
>mutable, AND you want Antoon's behaviour, then you get it for free just by
>using b.a += 1 instead of b.a = b.a + 1.
Not quite, because there is no way to avoid the binding of the __iadd__
return value to b.a by effective setattr (unless you make type(b).a
a descriptor that intercepts the attempt -- see another post for example).
Regards,
Bengt Richter
More information about the Python-list
mailing list