On Monday, February 26, 2018 at 3:44:14 PM UTC+1, Steven D'Aprano wrote: > I have a class with a large number of parameters (about ten) assigned in > `__init__`. The class then has a number of methods which accept > *optional* arguments with the same names as the constructor/initialiser > parameters. If those arguments are None, the defaults are taken from the > instance attributes. > > An example might be something like this: > > > class Foo: > def __init__(self, bashful, doc, dopey, grumpy, > happy, sleepy, sneezy): > self.bashful = bashful # etc > > def spam(self, bashful=None, doc=None, dopey=None, > grumpy=None, happy=None, sleepy=None, > sneezy=None): > if bashful is None: > bashful = self.bashful > if doc is None: > doc = self.doc > if dopey is None: > dopey = self.dopey > if grumpy is None: > grumpy = self.grumpy > if happy is None: > happy = self.happy > if sleepy is None: > sleepy = self.sleepy > if sneezy is None: > sneezy = self.sneezy > # now do the real work... > > def eggs(self, bashful=None, # etc... > ): > if bashful is None: > bashful = self.bashful > # and so on > > > There's a lot of tedious boilerplate repetition in this, and to add > insult to injury the class is still under active development with an > unstable API, so every time I change one of the parameters, or add a new > one, I have to change it in over a dozen places. > > Is there a good fix for this to reduce the amount of boilerplate? > > > Thanks, > > > > -- > Steve
What about something along these lines: from inspect import getargspec, getargvalues class Demo(object): def __init__(self, a=None, b=10, c='oops'): spec = getargspec(self.__init__) for key, value in zip(spec.args[1:], spec.defaults): setattr(self, key, value) def foo(self, *args, **kwargs): assert len(args) == 0 for k, v in kwargs.items(): try: getattr(self, k) except AttributeError: print('*** error: attribute {} does not exist.'.format(k)) setattr(self, k, v) d = Demo() print(d.a) d.foo(a=3.14) print(d.a) d.foo(q='this will raise') So, use the inspect module to detect the valid arguments from the class initializer. Then use **kwargs in every class method. It would be nice if the full method signature can be kept, but I have not yet figured out if this is possible. Marco -- https://mail.python.org/mailman/listinfo/python-list