#!/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.MethodTyp e( 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 NeverInOriginal Class( self, msg ):
return "Never in original class, id %d, %s: '%s'" % \
( id( self ), self.objname, msg )
def NewExistingMeth od( 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_cha nge)
# 'A' shows that we start with an existing method....
before_change.E xistingMethod( 'A' )
print "*** Replacing bound method 'ExistingMethod '..."
AddBoundMethod( cls, "ExistingMethod ", NewExistingMeth od )
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.E xistingMethod( 'B' )
after_change.Ex istingMethod( 'C' )
print "*** Adding new bound method 'AddedMethod'.. ."
AddBoundMethod( after_change.__ class__, "AddedMetho d",
NeverInOriginal Class )
# '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.A ddedMethod( 'D' )
print "%s" % after_change.Ad dedMethod( 'E' )
if __name__ == '__main__':
Test( OldStyleClass )
Test( NewStyleClass )
'''
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.MethodTyp e( 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 NeverInOriginal Class( self, msg ):
return "Never in original class, id %d, %s: '%s'" % \
( id( self ), self.objname, msg )
def NewExistingMeth od( 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_cha nge)
# 'A' shows that we start with an existing method....
before_change.E xistingMethod( 'A' )
print "*** Replacing bound method 'ExistingMethod '..."
AddBoundMethod( cls, "ExistingMethod ", NewExistingMeth od )
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.E xistingMethod( 'B' )
after_change.Ex istingMethod( 'C' )
print "*** Adding new bound method 'AddedMethod'.. ."
AddBoundMethod( after_change.__ class__, "AddedMetho d",
NeverInOriginal Class )
# '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.A ddedMethod( 'D' )
print "%s" % after_change.Ad dedMethod( 'E' )
if __name__ == '__main__':
Test( OldStyleClass )
Test( NewStyleClass )
Comment