string formatting with mapping & '*'... is this a bug?
Alex Martelli
aleaxit at yahoo.com
Sat Sep 11 02:48:05 EDT 2004
Andrew Dalke <adalke at mindspring.com> wrote:
...
> A "clever" (a-hem :) solution can use decorators.
True.
> It's hard to make the call signature correct though.
Maybe module inspect could help -- it's generally the best way to
introspect function signatures in Python. But, perhaps accepting some
sloppiness at the margins, we might code something like (untested!!!):
import itertools
def store_args(f):
co = f.func_code
args = co.co_varnames[1:co.co_argcount]
defs = dict(itertools.izip(reversed(args), f.func_defaults or ()))
def inner(self, *as, **kw):
kkw = dict(defs, **kw)
kkw.update(itertools.izip(args, as))
for kv in kkw.iteritems(): setattr(self, *kv)
return f(self, *as, **kw)
inner.__name__ = f.__name__
return inner
class foo:
@store_args
def __init__(self, a, b, c): pass
def __str__(self): return str(self.__dict__)
f = foo(1, 2, 3); print f
You could add sanity checks such as, f is not allowed a *foo argument
(it makes no sense in this context for f to get arguments of which it
does not know the names). But apart from such issues at the margins,
the signature check happens at inner's call to f -- if any arguments are
missing or not recognized, that call will raise. So, inner's job is
just to consider names and values with the right priority: defaults
first (least priority), then explicitly passed ones (either order since
they can't clash -- if they do the call to f will raise). Here, I build
the auxiliary dict kkw just that way.
I think I still prefer good old self.__dict__.update(locals()),
personally: it's way simpler. Of course, this one has some pluses, such
as calls to setattr rather than __dict__ updates, so it will work in
presence of __slots__, properties, or other weird descriptors, while my
favourite, simpler, more explicit solution doesn't.
Alex
More information about the Python-list
mailing list