Automatically initialize instance variables?

Viewed 48942

I have a python class that looks like this:

class Process:
    def __init__(self, PID, PPID, cmd, FDs, reachable, user):

followed by:

        self.PID=PID
        self.PPID=PPID
        self.cmd=cmd
        ...

Is there any way to autoinitialize these instance variables, like C++'s initialization list? It would spare lots of redundant code.

16 Answers

For Python 3.7+ you can use a Data Class, which is a very pythonic and maintainable way to do what you want.

It allows you to define fields for your class, which are your automatically initialized instance variables.

It would look something like that:

@dataclass
class Process:
    PID: int
    PPID: int
    cmd: str
    ...

The __init__method will already be in your class.

Note that here type hinting is required, that is why I have used int and str in the example. If you don't know the type of your field, you can use Any from the typing module.

The Data Class has many advantages compared to the proposed solutions:

  • It is explicit: all fields are visible, which respects the Zen of Python and makes it readable and maintainable. Compare it to the use of **kwargs.
  • It can have methods. Just like any other class.
  • It allows you to go beyond the automatic __init__ using the __post_init__ method.

EDIT: Reasons to avoid using NamedTuples

Some suggest the use of namedtuple for this case, but namedtuples have some behaviours that differs from Python classes, which are not really evident at first and should be well known:

1. NamedTuples are immutable

Immutability can be useful, but maybe it is not what you want for your instances. DataClasses can also be somehow immutable if you use the argument frozen=True on the @dataclass decorator.

2. NamedTuples __eq__ behaves like Tuple's

In Python, SomeNamedTuple(a=1, b=2) == AnotherNamedTuple(c=1, d=2) is True! The __eq__ function of NamedTuple, used in comparisons, only considers the values and the positions of those values on the compared instances, not their class or fields' names.

at the end of the init function:

for var in list(locals().keys()):
    setattr(self,var,locals()[var])

For more on setattr() please refer here

There is a helper function to do this in the fastcore lib https://fastcore.fast.ai/utils.html#store_attr.

from fastcore.utils import store_attr

class Process:
    def __init__(self, PID, PPID, cmd, FDs, reachable, user):
        store_attr() # this will do the same as self.PID = PID etc.
Related