py3k feature proposal: field auto-assignment in constructors

Arnaud Delobelle arnodel at googlemail.com
Mon Jan 28 13:09:48 CET 2008


On Jan 28, 4:47 am, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
wrote:
> En Sun, 27 Jan 2008 23:51:28 -0200, Arnaud Delobelle
> <arno... at googlemail.com> escribió:
>
> > Nice!  I've got a slight variation without magic argument names:
>
> > class Test(object):
> >      @autoassign('foo', 'bar')
> >      def __init__(self, baz):
> >          print 'baz =', baz
[...]
> I would like a signature-preserving version. The help system, pydoc, the
> inspect module, and likely any other introspection tool see those
> decorated methods with a different signature than the original one.
> Even if one writes a signature-preserving decorator (maybe along the lines
> of this article by M. Simionato [1]), names like "self_foo", "self_bar"
> are ugly. Furthermore, argument names are part of the public interfase,
> but here they're tied to the implementation: what if later I want to keep
> a reference to baz? I must change the argument name to self_baz, breaking
> all users of the code.

Sligthly improved (not for performance! but signature-preserving and
looks for default values)

from functools import wraps
from inspect import getargspec
from itertools import izip, chain

def autoassign(*names):
    def decorator(f):
        fargnames, _, _, fdefaults = getargspec(f)
        defaults = [(n,v) for (n,v)
                    in izip(reversed(fargnames), reversed(fdefaults))
                    if n in names]
        @wraps(f)
        def decorated(self, *args, **kwargs):
            self.__dict__.update(defaults)
            for name, arg in chain(izip(fargnames, args),
                                   kwargs.iteritems()):
                if name in names:
                    setattr(self, name, arg)
            return f(self, *args, **kwargs)
        return decorated
    return decorator

class Test(object):
     @autoassign('foo', 'bar')
     def __init__(self, foo, bar=3, baz=6):
         print 'baz =', baz

t = Test(1, 2, 6)
u = Test(foo=8)

print t.foo # 1
print t.bar # 2

print u.foo # 8
print u.bar # 3 (default)

--
Arnaud


print t.baz # AttributeError



More information about the Python-list mailing list