Whenever I'm defining a class which has a number of parameters I often find myself doing something like this
class myClass(object):
def __init__(self,param1,param2,param3, ...):
self.param1 = param1
self.param2 = param2
self.param3 = param3
...
My question is: is there a smarter, Pythonier way of doing this?
Thanks, Alex.
-
Might be smart, but if you're passing more than six arguments your code can get pretty ugly!Alex S– Alex S2012年11月21日 13:59:53 +00:00Commented Nov 21, 2012 at 13:59
-
What you're doing is most readable and Pythonic, IMO. Only in special circumstances would I use another option if there were a large number of attributes, for example.FogleBird– FogleBird2012年11月21日 14:00:21 +00:00Commented Nov 21, 2012 at 14:00
-
1If you're passing six arguments to a constructor and copy them into attributes without further processing, on a regular basis, you probably want to revisit your notion of a clean API and of good OOP style.user395760– user3957602012年11月21日 14:31:27 +00:00Commented Nov 21, 2012 at 14:31
-
To be quite honest, my background is numerical analysis and statistical physics, so usually i'm writing some code I want to run multiple times or to have some access to internal workings but it should be self-contained and reusable. I wouldn't NEED to use OO, yet I thought I might learn something as well. When you have for example a thermodynamical system, you'd have as parameters size, temperature, interaction strength, magnetic field, and whatnot. Maybe a class to represent the sytem and its dynamics is actually a bad idea, then.Alex S– Alex S2012年11月22日 11:45:13 +00:00Commented Nov 22, 2012 at 11:45
3 Answers 3
You could accept a variable number of named arguments and automatically set them, like this:
class MyClass(object):
def __init__(self, **kwargs): # variable named arguments
for k, v in kwargs.items():
setattr(self, k, v) # set the value of self.k to v, same as self.k = v
test = MyClass(param1="param1", param2="param2")
print test.param1 # "param1"
3 Comments
self.__dict__.update(kwargs). However I prefer this approach.You can pass your parameters as a keyword arguments: -
def __init__(self, **kwargs):
self.args = kwargs
Then you will instantiate your class like this: -
myClassObj = MyClass(a=12, b="abc")
Then your args dict will contain those arguments as key-value pair: -
{'a':12, 'b':'abc'}
to access the attributes: -
myClassObj.args['a']
myClassObj.args['b']
You can also pass a combination of various arguments. There are 4 kinds of arguments you can have in any function: -
- Positional Argument
- Default Argument
- Non-Keyword Argument
- Keyword argument.
In that order only. So the typical syntax of a function declaration is: -
def func(positional_arg, default_arg, *nkwargs, **kwargs)
See documentation for more on defining functions.
4 Comments
args, not multiple attributes.self.args accesses the dictionary. And then to access each argument: - self.args['a']You could do something like:
def __init__(self,*args):
_init_args = ('param1','param2','param3')
if len(_init_args) != len(args):
raise TypeError('__init__ takes {nargs} args'.format(nargs=len(_init_args)))
for k,v in zip(_init_args,*args):
setattr(self,k,v)
But I really don't think this is much better than your original solution or the solution posted by sean. The advantage of this over sean's answer is that the user doesn't need to know what the names of the attributes in your class are. It behaves a little bit more like a function declared:
def __init__(self,arg1,arg2,arg3):
...
Although there are still differences.