[EMAIL PROTECTED] wrote: > On Aug 2, 7:08 am, [EMAIL PROTECTED] wrote: >> On Aug 2, 6:49 am, [EMAIL PROTECTED] wrote: >> >> >> >>> Hi all, >>> It's possible that I'm missing the obvious -- I've been up for over 24 >>> hours and I'm most likely dehydrated from mass coffee intake, but I >>> figure many people in similar circumstances will be searching >>> comp.lang.python one day, so here goes! >>> class LibraryClass(object): >>> """ >>> A class whose implementation is out of my hands. >>> """ >>> def __init__(self): >>> """ >>> Follows good dynamic-language form and binds all instance >>> variables at initialization time. >>> """ >>> # Omitted: complex initialization functionality. >>> self.useful_attr = None >>> class MyInheritedClass(LibraryClass): >>> """ >>> My refinement of the functionality offered by the LibraryClass. I >>> now want the instance to initialize with a reference to an >>> external >>> object, and the useful_attr defined in the superclass will now >>> reference an attribute of that external object via fget. >>> Changing the attribute of the external object has undefined >>> behavior, so I want to omit an fset in the property declaration; >>> however, I have to provide some way for the superclass to >>> initialize useful_attr -- I can't change the superclass' code, as >>> it >>> resides in a library that is out of my hands. >>> """ >>> def __init__(self, external_obj): >>> LibraryClass.__init__(self) >>> self._external_obj = external_obj >>> def get_useful_attr(self): >>> return self._external_obj.proxy_useful_attr >>> useful_attr = property(fget=get_useful_attr) >>> def test(): >>> class _Fake(object): >>> pass >>> external_obj = _Fake() >>> external_obj.proxy_useful_attr = 12 >>> spam = MyInheritedClass(external_obj) >>> if __name__ == '__main__': >>> test() >>> EOF >>> If you're one of those people who doesn't like laboriously reading >>> contrived examples (elitists ;) I'll boil it down for you: Library >>> class initializes some attribute, but derived class wants to eliminate >>> fsets for said attribute. As a result, our ideal solution >>> Of course, this means that the derived class will raise an error in >>> some circumstances where the base class wouldn't (when you're setting >>> that attribute), but one can assume that the inheritance is >>> worthwhile. >>> How do I come up with silly solutions to circumvent this? Let me count >>> the ways... >>> 1. So-and-so: make an fset that does nothing. This ignores (what >>> should be) errors in code that uses MyInheritedClass in an attempt to >>> accommodate a useless statement in the base class -- surely non-ideal. >>> 2. The ugly one: since you can probably view the library, copy and >>> paste the complex initialization functionality in the above, but leave >>> out the bad statement. This not only forfeits the ideals of >>> inheritance, but makes you totally incompatible with future library >>> changes. >>> 3. Cheerleader: Pure evil. On top of the ugliness of 2, you assume >>> that across library revisions the indenting won't change and that the >>> troublesome statement will remain on the same line, and pull off one >>> of these babies: >>> def super_evil_test(): >>> from inspect import getsourcelines >>> exec(''.join([line[4:] for line in >>> getsourcelines(LibraryClass.__init__)[0][:-1]])) >>> LibraryClass.__init__ = __init__ >>> test() # Passes, but several angels no longer get their wings >>> Totally kidding, everybody! I hope Guido doesn't read this thread... >>> And this concludes the sleep deprived rambling that follows the >>> somewhat interesting case in point. Thoughts? >> I'm sorry -- the solution was not /enough/ coffee. Got another cup and >> sat down with the type/class unification doc, and found this thought- >> stimulating portion: >> >> http://www.python.org/download/releases/2.2/descrintro/#property >> If you want to override the __get__ operation for properties when used >> as a class attribute, you can subclass property - it is a new-style >> type itself - to extend its __get__ method, or you can define a >> descriptor type from scratch by creating a new-style class that >> defines __get__, __set__ and __delete__ methods. >> ... >> The get method won't be called when the property is accessed as a >> class attribute (C.x) instead of as an instance attribute (C().x). >> >> Seeing as how property is just a wrapper class, we don't need to >> declare it in the class body, though it /is/ the convention and the >> way it's done in all the docs I've seen. We fix our inherited class to >> be the following: >> >> [snip] >> class MyInheritedClass(LibraryClass): >> >> """ >> My refinement of the functionality offered by the LibraryClass. I >> now want the instance to initialize with a reference to an >> external >> object, and the useful_attr defined in the superclass will now >> reference an attribute of that external object via fget. >> >> Changing the attribute of the external object has undefined >> behavior, so I want to omit an fset in the property declaration; >> however, I have to provide some way for the superclass to >> initialize useful_attr -- I can't change the superclass' code, as >> it >> resides in a library that is out of my hands. >> """ >> >> def __init__(self, external_obj): >> LibraryClass.__init__(self) >> self.useful_attr = property(fget=self.get_useful_attr) >> self._external_obj = external_obj >> >> def get_useful_attr(self): >> return self._external_obj.proxy_useful_attr >> [snip] >> >> And it tests like a charm. > > Last post -- I swear. > > I failed to realize that it's all part of an extremely well defined > attribute resolution protocol, and handled via the descriptor > specification. Discussing descriptors was on the TODO list for the > type/class unification document, but there's a very fulfilling > explanation by Raymond Hettinger: > http://users.rcn.com/python/download/Descriptor.htm > Also, the official doc is here: http://docs.python.org/ref/descriptors.html > > Maybe the documentation for the property builtin should make reference > to the descriptor specification? If nobody thinks this is silly, I'll > submit a documentation patch in a few days. > > Sorry for the spam -- hope someone besides me learns from it! > And I hope you learn to get more sleep ;-)
short-on-sleep-myself-this-week-ly y'rs - steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 Holden Web LLC/Ltd http://www.holdenweb.com Skype: holdenweb http://del.icio.us/steve.holden --------------- Asciimercial ------------------ Get on the web: Blog, lens and tag the Internet Many services currently offer free registration ----------- Thank You for Reading ------------- -- http://mail.python.org/mailman/listinfo/python-list