Re: Adding bound methods dynamically... CORRECTED



#!/usr/bin/env python

# Sorry... :} cut/paste error fixed...

'''
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 )

.



Relevant Pages

  • Adding bound methods dynamically...
    ... #!/usr/bin/env python ... Is the solution coded in AddBoundMethod() ... def AddBoundMethod(cls, name, method): ... Dynamically add to the class 'cls' a bound method. ...
    (comp.lang.python)
  • urllib2.urlopen(req) error........
    ... some way incorrect...or is there a problem with Python on my hoster's ... urlopen>, req = ... 140 def install_opener: ... <bound method OpenerDirector.open of <urllib2.OpenerDirector ...
    (comp.lang.python)
  • Re: pythons OOP question
    ... be done in python? ... Ben Finney wrote: ... def v: ... In this case, 'o.m' is a bound method of a C2 instance, and has no ...
    (comp.lang.python)
  • Re: id() collisions on bound methods [was: metaclass and customization with parameters]
    ... def f: pass ... the bound method 'mc.method0' can be discarded (it is ... Python guarantees that two distinct objects alive *at the same time* ... 'False' (because they deal with the distinctness of immutable objects) ...
    (comp.lang.python)
  • text adventure question
    ... I am working on a text adventure game for python to get back into ... def character_sheet: ... global reputation ... print "Please choose another command. ...
    (comp.lang.python)