(I'm quoting the whole message below since this has been two weeks by now.) > From: =?iso-8859-1?Q?Gon=E7alo_Rodrigues?= <op73418@mail.telepac.pt> > > Hi all, > > Since this is my first post here, let me first introduce myself. I'm Gonçalo > Rodrigues. I work in mathematics, mathematical physics to be more precise. I > am a self-taught hobbyist programmer and fell in love with Python a year and > half ago. And of interesting personal details this is about all so let me > get down to business. > > My problem has to do with super that does not seem to work well with > properties. I posted to comp.lang.python a while ago and there I was advised > to post here. So, suppose I override a property in a subclass, e.g. > > >>> class test(object): > ... def __init__(self, n): > ... self.__n = n > ... def __get_n(self): > ... return self.__n > ... def __set_n(self, n): > ... self.__n = n > ... n = property(__get_n, __set_n) > ... > >>> a = test(8) > >>> a.n > 8 > >>> class test2(test): > ... def __init__(self, n): > ... super(test2, self).__init__(n) > ... def __get_n(self): > ... return "Got ya!" > ... n = property(__get_n) > ... > >>> b = test2(8) > >>> b.n > 'Got ya!' > > Now, since I'm overriding a property, it is only normal that I may want to > call the property implementation in the super class. But the obvious way (to > me at least) does not work: > > >>> print super(test2, b).n > Traceback (most recent call last): > File "<interactive input>", line 1, in ? > AttributeError: 'super' object has no attribute 'n' > > I know I can get at the property via the class, e.g. do > > >>> test.n.__get__(b) > 8 > >>> > > Or, not hardcoding the test class, > > >>> b.__class__.__mro__[1].n.__get__(b) > 8 > > But this is ugly at best. To add to the puzzle, the following works, albeit > not in the way I expected > > >>> super(test2, b).__getattribute__('n') > 'Got ya!' > > Since I do not know if this is a bug in super or a feature request for it, I > thought I'd better post here and leave it to your consideration. > > With my best regards, > G. Rodrigues Hah! I think I've resolved this, and I *still* don't know if it's a bug report or a feature request. :-) The crux of the matter is that super() has a specific exception for data descriptors, of which properties are an example. This means that when looking for attribute 'x', if it finds a hit which is a data descriptor, it ignores it and keeps looking. It took me a while to understand why. When I disabled the test, exactly *one* unit test fails, and it wasn't immediately clear what was going on. It turns out that this test was asking for the __class__ attribute of the super object itself, but it was getting the __class__ of the instance. Simplified: class C(object): pass print super(C, C()).__class__ This should print <type 'super'> and not <class '__main__.C'>, because it would be really confusing if the super object, when inquired about its class, masqueraded as another class. How does skipping data descriptors accomplish this goal? When super does its search, the last class it looks at is 'object', at the end of the MRO chain. And this has a data descriptor for '__class__', which describes the __class__ attribute of all objects. If super were to give this descriptor the usual treatment, it would call its __get__ method, and that would (in the above example) return the class C. The CVS history mentions (for typeobject.c rev 2.120, shortly before the final 2.2.0 release): super(C, C()).__class__ would return the __class__ attribute of C() rather than the __class__ attribute of the super object. This is confusing. To fix this, I decided to change the semantics of super so that it only applies to code attributes, not to data attributes. After all, overriding data attributes is not supported anyway. Your message above makes a good case for overriding data attributes, so I have to retract this. But I don't want __class__ to return C, I want it to return super. So I'll change this back, and make an explicit exception only for __class__. And ok, I'm deciding now that this is a feature, which means that I'm changing it in Python 2.3, but not backporting the change to Python 2.2.x. Hope this helps! --Guido van Rossum (home page: http://www.python.org/~guido/)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4