17

It's sometimes common in Python to see __init__ code like this:

class SomeClass(object):
    def __init__(self, a, b, c, d, e, f, g):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f
        self.g = g

especially if the class in question is purely a data structure with no behaviour. Is there a (Python 2.7) shortcut for this or a way to make one?

naiveai
  • 590
  • 2
  • 14
  • 42
  • 6
    If your class doesn't have any behaviour you could use a [**`namedtuple`**](https://docs.python.org/2/library/collections.html#collections.namedtuple) instead. – Peter Wood Nov 11 '16 at 10:37
  • @PeterWood Yeah, this works well for my purposes. You could post it as an answer so I can accept it. – naiveai Nov 11 '16 at 10:42
  • You're able to post an answer to your own question (c:. Make it nice, it'll get upvoted, and you can even accept it. I don't always have time to write nice answers, but enjoy gently pushing people in the right direction. – Peter Wood Nov 11 '16 at 11:39
  • @PeterWood Will do, was just wondering. – naiveai Nov 11 '16 at 12:10

4 Answers4

15

You could use Alex Martelli's Bunch recipe:

class Bunch(object):
    """
    foo=Bunch(a=1,b=2)
    """
    def __init__(self, **kwds):
        self.__dict__.update(kwds)
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    The trouble with this is that there's no way to control which properties are there. But it is a good general solution. – naiveai Nov 11 '16 at 10:34
  • 4
    As [Peter Wood suggests](http://stackoverflow.com/questions/40545922/is-there-a-python-shortcut-for-an-init-that-simply-sets-properties/40545993?noredirect=1#comment68330675_40545922), if you want a fixed number of named attributes, use a [namedtuple](https://docs.python.org/2/library/collections.html#collections.namedtuple) instead. – unutbu Nov 11 '16 at 10:41
  • 1
    This also doesn't support positional arguments. – ivan_pozdeev Nov 11 '16 at 15:03
10

You might find the attrs library helpful. Here's an example from the overview page of the docs:

>>> import attr
>>> @attr.s
... class SomeClass(object):
...     a_number = attr.ib(default=42)
...     list_of_numbers = attr.ib(factory=list)
...
...     def hard_math(self, another_number):
...         return self.a_number + sum(self.list_of_numbers) * another_number
>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
>>> sc.hard_math(3)
19

If you were using Python 3.8+, you could use dataclasses.

>>> from typing import List
>>> from dataclasses import dataclass, field
>>> @dataclass
... class OtherClass:
...     a_number: int=42
...     list_of_numbers: List[int] = field(default_factory=list)
...     def hard_math(self, another_number):
...         return self.a_number + sum(self.list_of_numbers) * another_number
>>> OtherClass=SomeClass
>>> oc = OtherClass(1, [1, 2, 3])
>>> oc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
>>> oc.hard_math(3)
19
Alasdair
  • 298,606
  • 55
  • 578
  • 516
4

Sure.

Class SomeClass(object):
    def __init__(self, **args):
        for(k, v) in args.items():
            setattr(self, k, v)

And v = SomeClass(a=1, b=2, c=3, d=4)

Bug it would make your code hard to understand.

Good Luck.

Jing
  • 1,090
  • 9
  • 13
  • 1
    This prevents easily setting defaults, doesn't it? You'd have to hardcode them in the function like `self.some_value = 123` which defeats the whole purpose of having a short and concise constructor function. – André Borie Nov 11 '16 at 14:00
2

You can make a class with a __new__ method that copies any class properties to to object, then inherit from that.

http://www.oreilly.com/programming/free/how-to-make-mistakes-in-python.csp has an example of why what I just said is a terrible idea that should be avoided.

(Short version: it doesn't work well with mutable objects, and the work-arounds for dealing with that are not worth the effort.)

roarsneer
  • 624
  • 6
  • 8