I have found it tedious to, when passing many variables to a class's constructor, assigning them all to self. This is a method to assign them automatically. It works with default arguments as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #The old way:
class Old:
def __init__(self, a, b, c, d, e, f, g, h, i=200, j=100):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
self.f = f
self.g = g
self.h = h
self.i = i
self.j = j
#The new way:
def setargstoself(inst, params):
code = inst.__init__.func_code
for item in code.co_varnames[1:code.co_argcount]:
setattr(inst, item, params[item])
class FooBar:
def __init__(self, a, b, c, d, e, f, g, h, i=200, j=100)
setargstoself(self, locals())
fb = FooBar(*range(9)) #set i, leave j as default
#An alternative implementation for functions with arguments *x or **y.
#However, this is less useful, because it would just be another 2 lines to
#assign each one of those to self.
#Here it is if anyone is interested.
import inspect
def setargstoself2(inst, params):
formal_args, var_args, kwd_args, unused = inspect.getargspec(inst.__init__)
for item in formal_args:
if item != 'self':
setattr(inst, item, params[item])
if var_args:
setattr(inst, var_args, params[var_args])
if kwd_args:
setattr(inst, kwd_args, params[kwd_args])
class FooBar2:
def __init__(self, a, b, c, *x, **y):
setargstoself2(self, locals())
fb2 = FooBar2(name='chloe', name2 = 'sam', *range(6))
|
Can stack inspection make it simpler ? Honestly, I have no plan to use this recipe. But the trick is very educative to me. Sure I'll visit this recipe again in the future.
BTW, I wonder if stack-related functions in the module inspect can make it even simpler. Just like how the zope.interface.implements works. Can we avoid all parameters to the function at all ? Wish someone give me an insight
What's wrong with the simple approach? What's wrong with this solution:
It has the advantage of NOT requiring any strange playing about with func_code and co_varnames. It's a trivial one-liner. It doesn't require creating a "setargstoself" function that needs to be imported (or repeated in every module). The only disadvantage is that it sets "self" to, well, self. If this is too painful, you can use a second line to delete that (but why bother... Python's GC can handle reference loops quite easily these days).
Educational, yes... ...but does it cut against the "explicit is better than implicit" ethic of python?
Maybe it's a C++-ism, but I actually like to lay out all those crazy variables in the __init__, and document them...
Debugging. I think it a great recipe because it can be used to debug how a __init__ method is called.
Another variant.
arrrgh! Sorry, the code from the above comment had a typo and would have introduced also another variable into the namespace (from the unassigned return value of the list comprehension).
So, baby, one more time:
I use inheritance and the doc string to avoid writing __init__ methods.