The __setattr__ attribute only assigns one attribute at a time, if you want to assign multiple attributes, you can use **kwargs in your function header and to limit the number of arguments you can simply check the length of kwargs inside your function. and call __setattr__ for each of the arguments one by one. One of the good reasons for this recipe is that, in principle, assigning an attribute to an object without considering anything is not a correct and desirable job due to a variety of reasons. Therefore, you must assign each attribute one at a time, considering all the necessary conditions.
You can also do this manually by updating the instance dictionary, but you must also handle exceptions.
In [80]: class foo: def bar(self, **kwargs): if len(kwargs) != 4: raise Exception("Please enter 4 keyword argument") for k, v in kwargs.items(): foo.__setattr__(self, k, v) ....: In [81]: f = foo() In [82]: f.bar(w=1, x=2, y=3, z=4) In [83]: fw Out[83]: 1 In [84]: f.bar(w=1, x=2, y=3, z=4, r=5) --------------------------------------------------------------------------- Exception Traceback (most recent call last) <ipython-input-84-758f669d08e0> in <module>() ----> 1 f.bar(w=1, x=2, y=3, z=4, r=5) <ipython-input-80-9e46a6a78787> in bar(self, **kwargs) 2 def bar(self, **kwargs): 3 if len(kwargs) != 4: ----> 4 raise Exception("Please enter 4 keyword argument") 5 for k, v in kwargs.items(): 6 foo.__setattr__(self, k, v) Exception: Please enter 4 keyword argument
Using __setatter__ , it will automatically take care of the exception:
In [70]: f.bar(1, 2) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-70-07d1f3c9e27f> in <module>() ----> 1 f.bar(1, 2) <ipython-input-65-1049e26120c1> in bar(self, *args) 2 def bar(self, *args): 3 for item in args: ----> 4 foo.__setattr__(self, item, item) 5 TypeError: attribute name must be string, not 'int'