This snippet defines a decorator to automate attributes setting in class instances at creation time. It can be seen as a gadget feature but it can also be handy especially for fast class prototyping.
Automating class instance attribute setting.
# Title: module autofill
# Author: Gribouillis, for the python forum at www.daniweb.com
# Date: 2011 Nov 02
# License: Public Domain
# Use this code freely in your programs.
from __future__ import print_function
from functools import update_wrapper
import inspect
"""Module to automate class instance attributes setting at creation.
This module offers a function autofill() which purpose is to replace
code similar to
class A(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
with
class A(object):
@ autofill()
def __init__(self, x, y, z):
pass
See the documentation of autofill() for details.
"""
va_enum = tuple("ignore store".split())
kw_enum = tuple("ignore store merge".split())
def autofill(va='ignore', kw='ignore'):
"""Return a decorator to implement automatic attribute setting in __init__ methods.
Typical use:
class A(object):
@ autofill()
def __init__(self, x, y):
pass
a = A(2, 3) # attributes a.x and a.y are automatically set.
Observe that the attributes are set *before* the body of __init__() is
executed.
The parameters 'va' and 'kw' influence the way variable number of arguments
and keywords arguments are handled in the __init__() method signature.
Possible values are 'ignore', 'store' for va, and 'ignore', 'store', 'merge'
for kw. For example if __init__() has the signature
def __init__(self, x, y, *uuu, **vvv)
then using autofill with 'ignore' for va and kw (the default) will cause uuu
and vvv to be ignored by the autofill mechanism. Passing va = 'store' will
create an attribute self.uuu. Similarly, passing kw = 'store' will create
self.vvv. Passing kw = 'merge' will not create self.vvv, but instead set a
new attribute for each pair (key, value) in vvv.
"""
if not va in va_enum:
raise ValueError(("Invalid va argument should be in", va_enum))
if not kw in kw_enum:
raise ValueError(("Invalid kw argument, should be in", kw_enum))
def decorator(func):
spec = inspect.getargspec(func)
# print "argspec:", spec
d = len(spec.args) - len(spec.defaults)
def wrapper(*args, **kwd):
# print "wrapper:", args, kwd
self = args[0]
n = len(args)
for i, name in enumerate(spec.args[1:], 1):
if i >= n:
if name in kwd:
value = kwd[name]
elif i >= d:
value = spec.defaults[i-d]
else: # ignore missing values. func() will complain
pass
else:
value = args[i]
setattr(self, name, value)
if spec.varargs is not None and va == 'store':
setattr(self, spec.varargs, args[len(spec.args):])
if spec.keywords is not None and kw != 'ignore':
pairs = ((k, v) for (k, v) in kwd.items() if k not in spec.args)
if kw == 'store':
setattr(self, spec.keywords, dict(pairs))
elif kw == 'merge':
for k, v in pairs:
setattr(self, k, v)
return func(*args, **kwd)
update_wrapper(wrapper, func)
return wrapper
return decorator
if __name__ == "__main__":
class A(object):
@ autofill(kw='merge')
def __init__(self, u, v=0, *xxx, **yyy):
pass
a = A(2, 3, z = 5)
print(vars(a))
Gribouillis 1,391 Programming Explorer Team Colleague
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.