Recipe20.8.Adding a Method to a Class Instance at Runtime


Recipe 20.8. Adding a Method to a Class Instance at Runtime

Credit: Moshe Zadka

Problem

During debugging, you want to identify certain specific instance objects so that print statements display more information when applied to those specific objects.

Solution

The print statement implicitly calls the special method _ _str_ _ of the class of each object you're printing. Therefore, to ensure that printing certain objects displays more information, we need to give those objects new classes whose _ _str_ _ special methods are suitably modified. For example:

def add_method_to_objects_class(object, method, name=None):     if name is None:         name = method.func_name     class newclass(object._ _class_ _):         pass     setattr(newclass, name, method)     object._ _class_ _ = newclass import inspect def _rich_str(self):     pieces = [  ]     for name, value in inspect.getmembers(self):         # don't display specials         if name.startswith('_ _') and name.endswith('_ _'):             continue         # don't display the object's own methods         if inspect.ismethod(value) and value.im_self is self:             continue         pieces.extend((name.ljust(15), '\t', str(value), '\n'))             return ''.join(pieces) def set_rich_str(obj, on=True):     def isrich( ):         return getattr(obj._ _class_ _._ _str_ _, 'im_func', None) is _rich_str     if on:         if not isrich( ):             add_method_to_objects_class(obj, _rich_str, '_ _str_ _')         assert isrich( )     else:         if not isrich( ):             return         bases = obj._ _class_ _._ _bases_ _         assert len(bases) == 1         obj._ _class_ _ = bases[0]         assert not isrich( )

Discussion

Here is a sample use of this recipe's set_rich_str function, guarded in the usual way:

if _ _name_ _ == '_ _main_ _':               # usual guard for example usage     class Foo(object):         def _ _init_ _(self, x=23, y=42):             self.x, self.y = x, y     f = Foo( )     print f     # emits: <_ _main_ _.Foo object at 0x38f770>     set_rich_str(f)     print f     # emits:     # x               23     # y               42     set_rich_str(f, on=False)     print f     # emits: <_ _main_ _.Foo object at 0x38f770>

In old versions of Python (and in Python 2.3 and 2.4, for backwards compatibility on instances of classic classes), intrinsic lookup of special methods (such as the intrinsic lookup for _ _str_ _ in a print statement) started on the instance. In today's Python, in the new object model that is recommended for all new code, the intrinsic lookup starts on the instance's class, bypassing names set in the instance's own _ _dict_ _. This innovation has many advantages, but, at a first superficial look, it may also seem to have one substantial disadvantage: namely, to make it impossible to solve this recipe's Problem in the general case (i.e., for instances that might belong to either classic or new-style classes).

Fortunately, that superficial impression is not correct, thanks to Python's power of introspection and dynamism. This recipe's function add_method_to_objects_class shows how to change special methods on a given object obj's class, without affecting other "sibling" objects (i.e., other instances of the same class as obj's): very simply, start by changing the obj's classthat is, by setting obj._ _class_ _ to a newly made class object (which inherits from the original class of obj, so that anything we don't explicitly modify remains unchanged). Once you've done that, you can then alter the newly made class object to your heart's contents.

Function _rich_str shows how you can use introspection to display a lot of information about a specific instance. Specifically, we display every attribute of the instance that doesn't have a special name (starting and ending with two underscores), except the instances' own bound methods. Function set_rich_str shows how to set the _ _str_ _ special method of an instance's class to either "rich" (the _rich_str function we just mentioned) or "normal" (the _ _str_ _ method the object's original class is coded to supply). To make the object's _ _str_ _ rich, set_rich_str uses add_method_to_objects_class to set _ _str_ _ to _rich_str. When the object goes back to "normal", set_rich_str sets the object's _ _class_ _ back to its original value (which is preserved as the only base class when the object is set to use _rich_str).

See Also

Recipe 20.6 and Recipe 20.7 for other cases in which a class' methods are modified; documentation on the inspect standard library module in the Library Reference.



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