Recipe20.13.Initializing Instance Attributes Without Using _ _init_ _


Recipe 20.13. Initializing Instance Attributes Without Using _ _init_ _

Credit: Dan Perl, Shalabh Chaturvedi

Problem

Your classes need to initialize some instance attributes when they generate new instances. If you do the initialization, as normal, in the _ _init_ _ method of your classes, then, when anybody subclasses your classes, they must remember to invoke your classes' _ _init_ _ methods. Your classes often get subclassed by beginners who forget this elementary requirement, and you're getting tired of the resulting support requests. You'd like an approach that beginners subclassing your classes are less likely to mess up.

Solution

Beginners are unlikely to have heard of the _ _new_ _ method, so you can place your initialization there, instead of in _ _init_ _:

# a couple of classes that you write: class super1(object):     def _ _new_ _(cls, *args, **kwargs):         obj = super(super1, cls)._ _new_ _(cls, *args, **kwargs)         obj.attr1 = [  ]         return obj     def _ _str_ _(self):         show_attr = [  ]         for attr, value in sorted(self._ _dict_ _.iteritems( )):             show_attr.append('%s:%r' % (attr, value))         return '%s with %s' % (self._ _class_ _._ _name_ _,                                ', '.join(show_attr)) class super2(object):     def _ _new_ _(cls, *args, **kwargs):         obj = super(super2, cls)._ _new_ _(cls, *args, **kwargs)         obj.attr2 = {  }         return obj # typical beginners' code, inheriting your classes but forgetting to # call its superclasses' _ _init_ _ methods class derived(super1, super2):     def _ _init_ _(self):         self.attr1.append(111)         self.attr3 = ( ) # despite the typical beginner's error, you won't get support calls: d = derived( ) print d # emits: derived with attr1:[111], attr2:{  }, attr3:( )

Discussion

One of Python's strengths is that it does very little magic behind the curtainsclose to nothing, actually. If you know Python in sufficient depth, you know that essentially all internal mechanisms are clearly documented and exposed. This strength, however, means that you yourself must do some things that other languages do magically, such as prefixing self. to methods and attributes of the current object and explicitly calling the _ _init_ _ methods of your superclasses in the _ _init_ _ method of your own class.

Unfortunately, Python beginners, particularly if they first learned from other languages where they're used to such implicit and magical behavior, can take some time adapting to this brave new world where, if you want something done, you do it. Eventually, they learn. Until they have learned, at times it seems that their favorite pastime is filling my mailbox with help requests, in tones ranging from the humble to the arrogant and angry, complaining that "my classes don't work." Almost invariably, this complaint means they're inheriting from my classes, which are meant to ease such tasks as displaying GUIs and communicating on the Internet, and they have forgotten to call my classes' _ _init_ _ methods from the _ _init_ _ methods of subclasses they have coded.

To deal with this annoyance, I devised the simple solution shown in this recipe. Beginners generally don't know about the _ _new_ _ method, and what they don't know, they cannot mess up. If they do know enough to override _ _new_ _, you can hope they also know enough to do a properly cooperative supercall using the super built-in, rather than crudely bypassing your code by directly calling object._ _new_ _. Well, hope springs eternal, or so they say. Truth be told, my hopes lie in beginners' total, blissful ignorance about _ _new_ _and this theory seems to work because I don't get those kind of help requests any more. The help requests I now receive seem concerned more with how to actually use my classes, rather than displaying fundamental ignorance of Python.

If you work with more advanced but equally perverse beginners, ones quite able to mess up _ _new_ _, you should consider giving your classes a custom metaclass that, in its _ _call_ _ (which executes at class instantiation time), calls a special hidden method on your classes to enable you to do your initializations anyway. That approach should hold you in good steadat least until the beginners start learning about metaclasses. Of course, "it is impossible to make anything foolproof, because fools are so ingenious" (Roger Berg). Nevertheless, see Recipe 20.14 for other approaches that avoid _ _init_ _ for attribute initialization needs.

See Also

Library Reference and Python in a Nutshell documentation on special methods _ _init_ _ and _ _new_ _, and built-in super; Recipe 20.14.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net