interface boilerplate
Michael Spencer
mahs at telcopartners.com
Mon Oct 18 13:07:06 EDT 2004
John Hunter wrote:
> In matplotlib, a plotting library with an OO API and a matlab-like
> procedural interface, I have a lot of functions defined in the matlab
> interface module that wrap similarly named class methods defined in
> the Axes class of the axes module. Eg, the Axes class defines a plot
> method and the matlab interface defines a plot function that gets the
> current Axes instance, calls the plot method on that instance, and
> does some error handling. Here is the matlab interface wrapper (gca()
> returns the current Axes instance)
>
> def plot(*args, **kwargs):
> try:
> ret = gca().plot(*args, **kwargs)
> except ValueError, msg:
> msg = raise_msg_to_str(msg)
> error_msg(msg)
> else:
> draw_if_interactive()
> return ret
> plot.__doc__ = Axes.plot.__doc__
>
> This is mostly boilerplate code that a lot of matlab interface
> functions use, and I'd like to automatically generate it.
>
> This appears to (mostly) work
>
> def _wrap_axfunc(name):
> def wrapper(*args, **kwargs):
> try:
> func = getattr(gca(), name)
> ret = func(*args, **kwargs)
> except ValueError, msg:
> msg = raise_msg_to_str(msg)
> error_msg(msg)
> else:
> draw_if_interactive()
> return ret
> wrapper.__doc__ = getattr(Axes, name).__doc__
> #wrapper.__name__ = name
> return wrapper
>
> plot = _wrap_axfunc('plot')
>
> The only problem I've seen so far is that the name of the function in
> pydoc string is 'wrapper', and I want it to appear as "plot". I tried
> setting the __name__ attribute, but it is read only.
>
> Any suggestions on how to best define these matlab interface functions
> by automatically wrapping the Axes instance functions? I'd like to
> support python2.2 so python2.2 compliant solutions especially welcome.
>
> JDH
John
The following descriptor-based delegation does not directly address your
question, but perhaps the idea is applicable. In any case, I'm curious
to get reactions to the approach. It may be well-known, but I haven't
seen a discussion of it in this group.
#Used on 2.3.3, but I think valid on 2.2+
class Delegate(object):
"""A descriptor that converts calls on obj, to calls on obj._data"""
def __init__(self, attr):
self.attr = attr
def __get__(self,obj,objtype = None):
return getattr(obj._data,self.attr) #Key step is here
#Example: wrap a subset of dict to get a read-only dict
class fdict(object):
"""Frozen Dictionary. Read only after init"""
def __init__(self,*args,**kw):
self._data = dict(*args,**kw)
def __repr__(self):
return "f"+repr(self._data)
"""Example - dict methods for read-only"""
fdictmethods = ['__cmp__', '__contains__', '__eq__', '__ge__',
'__getitem__','__gt__', '__iter__', '__le__', '__len__', '__lt__',
'__ne__','__reduce__','__reduce_ex__', '__str__', 'copy' , 'get',
'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues','keys','values']
"""Add each method as an auto-delegating descriptor"""
for attr in fdictmethods:
setattr(fdict,attr,Delegate(attr))
I like this because it's easy to automate, generates the the wrapper at
compile-time, and preserves the argspec of the wrapped functions
Michael
More information about the Python-list
mailing list