[Python-Dev] assymetry in descriptor behavior
David Abrahams
dave@boost-consulting.com
Sat, 22 Feb 2003 17:12:13 -0500
In trying to support user requests for C++-like behavior of wrapped
static data members, I noticed the following little assymetry:
>>> #define a property class
... class Prop(object):
... def __get__(self, obj, type=None):
... print '__get__', (self, obj, type)
... return 'value'
...
... def __set__(self, obj, type=None):
... print '__set__', (self, obj, type)
...
... def __delete__(self, obj, type=None):
... print '__delete__', (self, obj, type)
...
>>> # use it in a class Y
... class Y(object):
... x = Prop()
...
>>> a = Y()
>>> a.x # all accesses to a.x are intercepted
__get__ (<__main__.Prop object at 0x00877BC8>, <__main__.Y object at 0x00878108>, <class '__main__.Y'>)
'value'
>>> a.x = 42
__set__ (<__main__.Prop object at 0x00877BC8>, <__main__.Y object at 0x00878108>, 42)
>>> Y.x # Prop intercepts reads of the class attribute
__get__ (<__main__.Prop object at 0x00877BC8>, None, <class '__main__.Y'>)
'value'
>>> Y.x = 1 # But not assignments
>>> Y.x
1
>>> class mc(object.__class__): # to intercept Y.x assignment
... x = Prop() # I have to define this
...
>>> class Y(object):
... __metaclass__ = mc
...
>>> Y.x # now all accesses to Y.x are intercepted
__get__ (<__main__.Prop object at 0x00876AB8>, <class '__main__.Y'>, <class '__main__.mc'>)
'value'
>>> Y.x = 1
__set__ (<__main__.Prop object at 0x00876AB8>, <class '__main__.Y'>, 1)
>>> a = Y() # But not accesses to a.x
>>> a.x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'Y' object has no attribute 'x'
>>>
As you can see, the only way to intercept assignment to Y.x is to
stick a property Y's class, i.e. the metaclass (or to modify
__setattr__ in the metaclass, but it amounts to the same thing).
In C++, a mutable static data member can be modified via the class
Y::x = 1;
or an instance of the class
a.x = 1;
I notice that Python supports this sort of dual access for reading
attributes and calling static functions, but getting that behavior for
mutable attributes seems unreasonably difficult: I need a property in
the metaclass *and* in the class.
1. To throw out a straw-man suggestion, what about adding an
additional protocol __set2__ which, if found, will be called
instead of __set__ both for reading _and_ writing attributes on the
class?
2. What are the optional type=None arguments for? It seems as though
only the middle argument (obj) is ever None. I just copied this
protocol out of descrintro.html
3. Is there documentation for __delete__ anywhere?
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com