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

run-time construction of methods

P: n/a
Hello all.

I am in the need of wrapping certain objects at run-time. My initial
approach was:

import inspect, new
def make_wrapper(obj, methodName):
cls = obj.__class__
wrapmth = getattr(obj, methodName)
print "************ ", methodName
def wrapper(self, *args, **kwargs):
print "**before ", methodName
return wrapmth(*args, **kwargs)
return wrapper

class Person(object):
def __init__(self, age):
super(Person, self).__init__()
self.age = age

def getAge(self):
return self.age

def setAge(self, newage):
"""sets the age of the person"""
self.age = newage

p = Person(33)
setattr(p, "setAge", new.instancemethod(make_wrapper(p,"setAge"), p,
p.__class__))
p.setAge(22)
print "age is ", p.getAge()

However, reflectional information is gone, such as the __doc__ string, and
in an interactive environment, when typing a method call of setAge() the
arguments are specified as "(..., ***)" rather than "(newage)"

I have thus attempted to replace the make_wrapper function with a version
where the inner function "wrapper" is a string which gets translated into
a function with an identical signature as the method to wrap.. my closest
attempt to a real solution is
def make_wrapper(obj, methodName):
cls = obj.__class__
wrapmth = getattr(obj, methodName)
print "************ ", methodName
wrapperstr = """def wrapper(self, *args, **kwargs):
print "**before ", methodName
return wrapmth(*args, **kwargs)"""
exec(wrapperstr, globals(), locals())
return wrapper

but I get the error

NameError: global name 'methodName' is not defined

which I don't know how to deal with... inspecting the locals() a
'methodName' is defined.. Note that my above 'solution' is far from the
product I want, I just figured I needed to get this to work, before
fidling with the signature stuff...
does anyone have an idea on how to approach this?
-Carlo
--
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 18 '05 #1
Share this Question
Share on Google+
1 Reply


P: n/a
"Carlo v. Dango" <oe**@soetu.eu> writes:
Hello all.

I am in the need of wrapping certain objects at run-time. My initial
approach was:

import inspect, new
def make_wrapper(obj, methodName):
cls = obj.__class__
wrapmth = getattr(obj, methodName)
print "************ ", methodName
def wrapper(self, *args, **kwargs):
print "**before ", methodName
return wrapmth(*args, **kwargs)
return wrapper

class Person(object):
def __init__(self, age):
super(Person, self).__init__()
self.age = age

def getAge(self):
return self.age

def setAge(self, newage):
"""sets the age of the person"""
self.age = newage

p = Person(33)
setattr(p, "setAge", new.instancemethod(make_wrapper(p,"setAge"), p,
p.__class__))
p.setAge(22)
print "age is ", p.getAge()
I like the approach of using a bound method to p to create a
new instance specific method for p.
...
def make_wrapper(obj, methodName):
cls = obj.__class__
wrapmth = getattr(obj, methodName)
print "************ ", methodName
wrapperstr = """def wrapper(self, *args, **kwargs):
print "**before ", methodName
return wrapmth(*args, **kwargs)"""
exec(wrapperstr, globals(), locals())
return wrapper

but I get the error

NameError: global name 'methodName' is not defined

exec does not create a closure within the function calling it.
That is its downside. So everything is either local to wrapmth,
eg. parameters and variables created within the function, or
global. Fortunately you can still create a closure with exec
by declaring a function within a function. Here's my rewrite.
I hope it works for you.

def make_wrapper(obj, methodName):
cls = obj.__class__
wrapmth = getattr(obj, methodName)
print "********** ", methodName
wrapperstr = """\
def _closure(_wrapmth):
def wrapper(self, *args, **kwds):
"I wrap method %(methodName)s"
print "**before %(methodName)s"
return _wrapmth(*args, **kwds)
return wrapper
_wrapper = _closure(wrapmth)
""" % {'methodName': methodName} # Insert strings directly into code
locs = {'wrapmth': wrapmth} # Keep namespace clean to avoid conflicts
exec(wrapperstr, {}, locs)
return locs['_wrapper'] # and here is the result

See how the argument to _closure is the 'local' you want to keep
around. Also I don't use globals() or locals() directly since
they are cluttered. When you start trying to make the parameters
of wrapper meaningful you will want to minimize the chance
the parameter names conflict with other names within the scope
of the exec. That is also why _closure and _wrapmth begin
with underscores. You might want to choose even more cryptic names.
Also, inlining strings such as methodName instead of passing them
as variables into the exec scope reduces the chance of conflict.

Lenard Lindstrom
<le***@telus.net>
Jul 18 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.