Credit: Ken Seehof
You need to globally change the behavior of existing classes in a
third-party library—for example, by wrapping existing
_ _init_ _
methods.
Avoid 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( )
Once 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.
Recipe 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).