#!/usr/bin/env python ''' I want to dynamically add or replace bound methods in a class. I want the modifications to be immediately effective across all instances, whether created before or after the class was modified. I need this to work for both old ('classic') and new style classes, at both 2.3 and 2.4. I of course want to avoid side effects, and to make the solution as light-weight as possible.
Question for the experts: Is the solution coded in AddBoundMethod() acceptable to the Pythonian Gods? :) It does seem to work -- tested at 2.3.5 (RH Linux) and 2.4.1 (WinXP) Is there a more pythonic way that's as straight forward? ''' def AddBoundMethod( cls, name, method ): ''' Dynamically add to the class 'cls' a bound method. Invoking this method instantly adds (or overwrites) the bound method identified by 'name' with the code contained in 'method', EVEN FOR PRE-EXISTING INSTANCES OF THE CLASS. The 'method' parameter should be a non-class function that has 'self' as its first parameter. ''' try: types except NameError: import types # # this is the crux of this example, short and sweet... # exec "%s.%s = types.MethodType( method, None, %s )" \ % ( cls.__name__, name, cls.__name__ ) # # The remainder (50x longer than the solution!) is test code... # # one new-style class... class NewStyleClass( object ): def __init__ ( self, objname ): print "Created a NewStyleClass, id %d, %s" % \ ( id( self ), objname ) self.objname = objname def ExistingMethod( self, msg ): print "Original ExistingMethod, id %d, %s: '%s'" % \ ( id( self ), self.objname, msg ) # one 'classic' style class... class OldStyleClass: def __init__ ( self, objname ): print "Created a OldStyleClass, id %d, %s" % \ ( id( self ), objname ) self.objname = objname def ExistingMethod( self, msg ): print "Original ExistingMethod, id %d, %s: '%s'" % \ ( id( self ), self.objname, msg ) # two non-class functions that *look* like bound methods in a class; # one returns a value, the other just outputs a string... def NeverInOriginalClass( self, msg ): return "Never in original class, id %d, %s: '%s'" % \ ( id( self ), self.objname, msg ) def NewExistingMethod( self, msg ): print "REPLACED ExistingMethod, id %d, %s: '%s'" % \ ( id( self ), self.objname, msg ) # a test routine... def Test( cls ): print "--- %s ----------------------------------------------" % \ cls.__name__ print "type of class %s is '%s'" % ( cls.__name__, type( cls ) ) before_change = cls('instance created before change') print "type of object before_change is '%s'" % type(before_change) # 'A' shows that we start with an existing method.... before_change.ExistingMethod( 'A' ) print "*** Replacing bound method 'ExistingMethod'..." AddBoundMethod( cls, "ExistingMethod", NewExistingMethod ) after_change = cls( 'instance created AFTER change' ) print "type of after_change is '%s'" % type( after_change ) # 'B' and 'C' show we've replaced an existing method, both on # pre-existing instances and instances created after using # AddBoundMethod() before_change.ExistingMethod( 'B' ) after_change.ExistingMethod( 'C' ) print "*** Adding new bound method 'AddedMethod'..." AddBoundMethod( after_change.__class__, "AddedMethod", NeverInOriginalClass ) # 'D' and 'E' show we've added a brand new method, both on # pre-existing instances and instances created after using # AddBoundMethod() print "%s" % before_change.AddedMethod( 'D' ) print "%s" % after_change.AddedMethod( 'E' ) if __name__ == '__main__': Test( OldStyleClass ) Test( NewStyleClass ) -- http://mail.python.org/mailman/listinfo/python-list