On 14 Mar 2005 13:07:29 -0800, "Martin Miller" <[EMAIL PROTECTED]> wrote:
>Bengt Richter wrote, in part: >> On 14 Mar 2005 01:19:23 -0800, "Martin Miller" ><[EMAIL PROTECTED]> >> wrote, in part: >> >What still puzzles me, though, is why all the above to make >properties >> >work on instances is necessary in the first place. It's certainly >not >> >clear (to me) from what is said in the How-to at: >> >> >> >>http://users.rcn.com/python/download/Descriptor.htm#invoking-descriptors >> >I suspect that it may be simply a performance issue, in other words, >it >> >was considered too slow to check for instance property/discriptors >-- >> >although *why* is not clear to me. >> >> I suspect the desired semantics re precedence have evolved to make >normal >> programs easily implementable, and that probably drove the >implementation: >> """ >> For objects, the machinery is in object.__getattribute__ which >transforms >> b.x into type(b).__dict__['x'].__get__(b, type(b)). >> The implementation works through a precedence chain that gives (my >added >> [1,2,3]) >> >> [1] data descriptors priority over instance variables, >> [2] instance variables priority over non-data descriptors, >> [3] and assigns lowest priority to __getattr__ if provided. >> >> The full C implementation can be found in PyObject_GenericGetAttr() >in >> Objects/object.c. >> """ > >I haven't examined the C code in Objects/object.c to see *how* the >semantics are implemented because that's not really the point...which >is the descriptions of what's suppose to happen don't seem to match >what actually does. To illustrate, consider: >> class Foobar(object): >> pass >> >> def myget(self, obj, type=None): >> return 42 >> >> def myset(self, value): >> raise AttributeError("this is a read-only property") >> >> foobar = Foobar() >> foobar.x = property(myget, myset) >> >> print "foobar.x:", foobar.x > >Which prints: >> foobar.x: <property object at 0x00AE5850> > >Ignoring "why" issue, my question becomes: > >foobar.x is a data descriptor property, however object.__getattribute__ It is a property, and it has the requisite methods (__get__ and __set__) to be a data descriptor, but it is not a data descriptor unless it is visible as an attribute of type(foobar), which foobar.x is not. >does *not* seem to be treating it as such and handling it the way >described either by you or in what is written in the how-to. >Specifically the statements that: >> For objects, the machinery is in object.__getattribute__ which >transforms >> b.x into type(b).__dict__['x'].__get__(b, type(b)). > >This doesn't seem to be occuring. Am I missing something? > I think so. Following your example: >>> class Foobar(object): ... pass ... >>> def myget(self, obj, type=None): ... return 42 ... >>> def myset(self, value): ... raise AttributeError("this is a read-only property") ... >>> foobar = Foobar() >>> foobar.x = property(myget, myset) >>> print "foobar.x:", foobar.x foobar.x: <property object at 0x02EF0644> >>> >>> type(foobar).__dict__['x'] Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'x' meaning b.x into type(b).__dict__['x'].__get__(b, type(b)). does not apply, and the attempt to get foobar.x falls back to ordinary attribute access. I.e., foobar.x will be whatever BTW, I'm not sure type(b).__dict__['x'].__get__(b, type(b)) is really fully correct, since that would not find foobar.x in a Foobar base class: >>> class Base(object): pass ... >>> Base.x = property(myget, myset) >>> class Sub(Base): pass ... >>> sub = Sub() >>> sub.x Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: myget() takes at least 2 arguments (1 given) (At least it was found, even if the signature is bad ;-) But: >>> type(sub).__dict__['x'] Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'x' So the real truth chases down the mro chain before giving up and falling back to ordinary attribute access, IWT. Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list