Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > run-time construction of methods

Reply
Thread Tools

run-time construction of methods

 
 
Carlo v. Dango
Guest
Posts: n/a
 
      04-06-2004
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/
 
Reply With Quote
 
 
 
 
Lenard Lindstrom
Guest
Posts: n/a
 
      04-07-2004
"Carlo v. Dango" <(E-Mail Removed)> 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
<(E-Mail Removed)>
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Under Construction logo or icon Woody Splawn ASP .Net 4 07-14-2009 12:39 PM
Is there a way to find the class methods of a class, just like'methods' finds the instance methods? Kenneth McDonald Ruby 5 09-26-2008 03:09 PM
Default construction versus construction with initial values Ook C++ 10 10-08-2005 09:00 PM
QueryString construction TCORDON ASP .Net 2 06-15-2005 09:30 PM
Programmatic construction of httprequest? Bill Cohagan ASP .Net 19 08-18-2004 05:31 PM



Advertisments