py3k feature proposal: field auto-assignment in constructors
Arnaud Delobelle
arnodel at googlemail.com
Mon Jan 28 14:19:33 EST 2008
On Jan 28, 4:08 pm, "André" <andre.robe... at gmail.com> wrote:
[...]
> If I may suggest, I would extend this so that autoassign's signature
> would be as follows:
>
> autoassign(all=True, include_only=None, exclude=None)
>
> Either one of include_only or exclude could be a list of function to
> which the automatic assignment would apply (or not). I was planning
> to write this up and submit it to the cookbook later this evening, but
> since the suggestion has been made, someone else can jump on it. ;-)
>
> André
I've modified my little decorator (see Test1, Test2, Test3 for
usage). I'll post it later on the cookbook if there seems to be no
bugs and noone raises valid point against it:)
from functools import wraps
from inspect import getargspec, isfunction
from itertools import izip, ifilter, starmap
def autoassign(*names, **kwargs):
if kwargs:
exclude, f = set(kwargs['exclude']), None
sieve = lambda l:ifilter(lambda nv: nv[0] not in exclude, l)
elif len(names) == 1 and isfunction(names[0]):
f = names[0]
sieve = lambda l:l
else:
names, f = set(names), None
sieve = lambda l: ifilter(lambda nv: nv[0] in names, l)
def decorator(f):
fargnames, _, _, fdefaults = getargspec(f)
# Remove self for fargnames and make sure fdefaults is a tuple
fargnames, fdefaults = fargnames[1:], fdefaults or ()
defaults = list(sieve(izip(reversed(fargnames),
reversed(fdefaults))))
@wraps(f)
def decorated(self, *args, **kwargs):
assigned = dict(sieve(izip(fargnames, args)))
assigned.update(sieve(kwargs.iteritems()))
# It would be nice to have a builtin to exhaust iterators:
for _ in starmap(assigned.setdefault, defaults): pass
self.__dict__.update(assigned)
return f(self, *args, **kwargs)
return decorated
return f and decorator(f) or decorator
class Test(object):
@autoassign('foo', 'bar')
def __init__(self, foo, bar=3, baz=6):
print 'baz =', baz
class Test2(object):
@autoassign
def __init__(self, foo, bar): pass
class Test3(object):
@autoassign(exclude=('foo', 'bar'))
def __init__(self, foo, bar, baz=5, **kwargs): pass
t = Test(1, 2, 5)
u = Test(foo=8)
v = Test2(10, 11)
w = Test3(100, 101, foobar=102)
print t.foo # 1
print t.bar # 2
print u.foo # 8
print u.bar # 3 (default)
print v.foo, v.bar # 10 11
print w.baz, w.foobar # 5 102
for obj, attr in ('w', 'foo'), ('w', 'bar'), ('t', 'baz'):
try:
getattr(globals()[obj], attr)
except AttributeError:
print '%s.%s raises AttributeError' % (obj, attr)
==== output ====
baz = 5
baz = 6
1
2
8
3
10 11
5 102
w.foo raises AttributeError
w.bar raises AttributeError
t.baz raises AttributeError
--
Arnaud
More information about the Python-list
mailing list