By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,498 Members | 1,564 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,498 IT Pros & Developers. It's quick & easy.

Adding bound methods dynamically...

P: n/a
#!/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 )

Aug 31 '05 #1
Share this Question
Share on Google+
8 Replies


P: n/a
#!/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 )

Aug 31 '05 #2

P: n/a
Kevin Little wrote:
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)

[code]


I'm not an expert, but why do you need to dynamically add or replace
bound methods?

Aug 31 '05 #3

P: n/a
Kevin Little wrote:
I want to dynamically add or replace bound methods in a class. I want

I asked a seemingly-unrelated question a week or so ago, and learned
something interesting:

Python 2.3.4 (#2, Jul 12 2004, 12:46:36)
[GCC 3.3] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
def foo(self): ... print "foo called"
... class C(object): ... pass
... type(foo) <type 'function'> C.foo = foo
type(C.foo) <type 'instancemethod'> c = C()
c.foo() foo called type(c.foo) <type 'instancemethod'>


I.e. assigning a normal function object to a class object turns it into
a member function!

You can read more in the thread with the subject 'keeping a ref to a
non-member function in a class'.
Aug 31 '05 #4

P: n/a
Devan L wrote:
Kevin Little wrote:
I want to dynamically add or replace bound methods in a class.

(snip)
I'm not an expert, but why do you need to dynamically add or replace
bound methods?


To modify the behaviour at runtime ?-)

There are a lot of idioms/patterns in dynamic languages that seems
somewhat alien at first, then become an obvious solution. When I
discovered first-class functions and anonymous functions with Python
some years ago, I wondered what could be the use of such things. Now I
couldn't live without...

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Aug 31 '05 #5

P: n/a
bruno modulix <on***@xiludom.gro> writes:
Devan L wrote:
Kevin Little wrote:
I want to dynamically add or replace bound methods in a class.


(snip)
I'm not an expert, but why do you need to dynamically add or replace
bound methods?


To modify the behaviour at runtime ?-)

There are a lot of idioms/patterns in dynamic languages that seems
somewhat alien at first, then become an obvious solution. When I
discovered first-class functions and anonymous functions with Python
some years ago, I wondered what could be the use of such things. Now I
couldn't live without...


Yes, but rather than going through the contortions you do to bind a
new method into place, why not make the method in question act as a
proxy for the real method? After all, with first-class functions,
that's easy.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Sep 1 '05 #6

P: n/a
>
Yes, but rather than going through the contortions you do to bind a
new method into place, why not make the method in question act as a
proxy for the real method? After all, with first-class functions,
that's easy.


Because you don't have to write that proxy. Pure lazyness :)
Diez
Sep 1 '05 #7

P: n/a
Mike Meyer wrote:
bruno modulix <on***@xiludom.gro> writes:
Devan L wrote:
Kevin Little wrote:
I want to dynamically add or replace bound methods in a class.
(snip)

I'm not an expert, but why do you need to dynamically add or replace
bound methods?


To modify the behaviour at runtime ?-)

(snip)
Yes, but rather than going through the contortions you do to bind a
new method into place,
Contortion ? Which contortion ?

class Foo(object):
def __init__(self, name):
self.name = name

def greet1(self, who):
print "hello %s, this is %s" % (who, self.name)

def greet2(self, who):
print "Yo %s, have a drink with Daddy %s" % (who, self.name)

f = Foo('Python')

Foo.greet = greet1
f.greet('Monty')
Foo.greet = greet2
f.greet('Monty')
why not make the method in question act as a
proxy for the real method?


Please show us an implementation.
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'on***@xiludom.gro'.split('@')])"
Sep 1 '05 #8

P: n/a
Kevin Little a écrit :

Oops, sorry, forgot to answer
'''
I want to dynamically add or replace bound methods in a class. (snip) Is there a more pythonic way that's as straight forward?


What's wrong with:

class Foo:
pass

def method(self):
print "%s" % self

f = Foo()
Foo.method = method
f.method()
Sep 1 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.