I l@ve RuBoard |
15.7 Modifying Methods in PlaceCredit: Ken Seehof 15.7.1 ProblemYou need to globally change the behavior of existing classes in a third-party library�for example, by wrapping existing _ _init_ _ methods. 15.7.2 SolutionAvoid the antipattern of modifying library code, even though you have source for it, or you'll be forever chasing upgrades to the library and reapplying your changes to each release. Python's introspection lets you noninvasively obtain the same desired effect without changing the library's source code: # needs Python 2.1 or later from _ _future_ _ import nested_scopes import new def enhance_ _init_ _(klass, f): try: ki = klass._ _init_ _ except AttributeError: def ki(self, *args, **kwds): pass klass._ _init_ _ = new.instancemethod( lambda *args, **kwds: f(ki, *args, **kwds), None, klass) def demo( ): class X: def _ _init_ _(self, v): self.v = v def g(_ _init_ _, self, v): _ _init_ _(self, v) self.parrot='dead' enhance_ _init_ _(X, g) x = X(2) print x.parrot demo( ) 15.7.3 DiscussionOnce in a while it becomes necessary to globally change the behavior of classes in a third-party library, ideally without modifying the source code for that library. This recipe demonstrates the ability to modify the _ _init_ _ method of an arbitrary class in place at runtime by wrapping the method in any given metafunction. In my experience, this approach is also good for making functional programmers wince, which can be entertaining. Of course, many other forms of currying besides the lambda used in this recipe could be used to build the underlying function for the enhanced method. 15.7.4 See AlsoRecipe 15.8 for currying in general; Recipe 5.14 and Recipe 15.10 for other examples of modifying the methods of an instance; antipatterns (patterns that tell how to go from a problem to a bad solution) are discussed in detail on the Portland Pattern WikiWiki (http://c2.com/cgi/wiki?AntiPatterns). |
I l@ve RuBoard |