|I l@ve RuBoard|
15.11 Adding a Method to a Class Instance at Runtime
Credit: an anonymous contributor, Moshe Zadka
During debugging, you want to identify certain specific instance objects so that print statements display more information when applied to those objects.
import string import new def rich_str(self): classStr = '' for name, value in self._ _class_ _._ _dict_ _.items( ) + self._ _dict_ _.items( ): classStr += string.ljust(name, 15) + '\t' + str(value) + '\n' return classStr def addStr(anInstance): anInstance._ _str_ _ = new.instancemethod(rich_str, anInstance, anInstance._ _class_ _) # Test it class TestClass: classSig = 'My Sig' def _ _init_ _(self, a = 1, b = 2, c = 3): self.a = a self.b = b self.c = c test = TestClass( ) addStr(test) print test
This recipe demonstrates the runtime addition of a _ _str_ _ special method to a class instance. Python calls obj._ _str_ _ when you ask for str(obj) or when you print obj. Changing the _ _str_ _ special method of obj lets you display more information for the specific instance object in question when the instance is printed during debugging.
The recipe as shown is very simple and demonstrates the use of the special attributes _ _dict_ _ and _ _class_ _. A serious defect of this approach is that it creates a reference cycle in the object. Reference cycles are no longer killers in Python 2.0 and later, particularly because we're focusing on debugging-oriented rather than production code. Still, avoiding reference cycles, when feasible, makes your code faster and more responsive, because it avoids overloading the garbage-collection task with useless work. The following function will add any function to an instance in a cycle-free way by creating a specially modified class object and changing the instance's class to it:
def add_method(object, method, name=None): if name is None: name = method.func_name class newclass(object._ _class_ _): pass setattr(newclass, name, method) object._ _class_ _ = newclass
We could also use the new module to generate the new class object, but there is no particular reason to do so, as the class statement nested inside the add_method function suits our purposes just as well.
With this auxiliary function, the addStr function of the recipe can, for example, be more effectively (and productively) coded as:
def addStr(anInstance): add_method(anInstance, rich_str, '_ _str_ _')
The second approach also works for new-style classes in Python 2.2. The _ _class_ _ attribute of such an instance object is assignable only within certain constraints, but because newclass extends the object's existing class, those constraints are met (unless some strange metaclass is in use). In Python 2.2, operations on instances of new-style classes don't use special methods bound in the instance, but only special methods bound in the class (in all other cases, per-instance binding still override per-class bindings).
15.11.4 See Also
|I l@ve RuBoard|