string formatting with mapping & '*'... is this a bug?

Alex Martelli aleaxit at
Sat Sep 11 08:48:05 CEST 2004

Andrew Dalke <adalke at> wrote:
> A "clever" (a-hem :) solution can use decorators.


> 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:
    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.


More information about the Python-list mailing list