Modifying Methods in Place
Credit: Ken Seehof
Problem
You need to globally change the behavior of existing classes in a
third-party library—for example, by wrapping existing
_ _init_ _ methods.
Solution
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( )Discussion
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 ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access