4

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.

4
  • Might be smart, but if you're passing more than six arguments your code can get pretty ugly! Commented 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. Commented Nov 21, 2012 at 14:00
  • 1
    If 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. Commented 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. Commented Nov 22, 2012 at 11:45

3 Answers 3

9

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"

setattr documentation

Sign up to request clarification or add additional context in comments.

3 Comments

It's a bit convoluted, but it surely gets the job done. Problem is I'd probably have to check if the attribute has defined everytime I use it. Thanks, though!
Since this is in the constructor the object it self will not have the attributes at this time so a check is not required.
Another thing which you'll sometimes see is self.__dict__.update(kwargs). However I prefer this approach.
3

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

Then I can reference self.a and self.b inside the class later on?
But this doesn't produce the desired result. There will be only one attribute args, not multiple attributes.
@AlexS.. No, self.args accesses the dictionary. And then to access each argument: - self.args['a']
@LevLevitsky.. YEah and since that attribute is a dictinary, it can store all those attributes in it, and then we can access it. See my edited post.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.