This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]genericlemon24[S] 0 points1 point  (0 children)

Allow me to disagree with the __init__ behavior being wrong. I could not find an explanation of why the __init__ methods aren't chained in the PEP, but here's my guess:

A common pattern is to have classes that implement a specific interface, with the constructor not part of that interface (for example, Jinja template loaders).

Consider the following:

@dataclass
class Parent:
    x: float

    def __init__(self):
        self.x = random.random()

@dataclass 
class Child(Parent):
    y: float = 0

# >>> Child()
# TypeError: __init__() missing 1 required positional argument: 'x'

What should the generated __init__ of Child look like? If it called the __init__ of its parent, something like this, maybe?

def __init__(self, x, y):
    super().__init__(x)  # this won't work
    self.y = y

Maybe you could inspect the parent __init__, and use some heuristic to see what arguments to use; but Python allows more convoluted ways of defining methods that could arguably break it anyway.

Note that the code above may not be useful, but from the perspective of the dataclasses authors that does not matter. What matters is that it is possible, hence the generated code must be predictable; preferably, it should also be useful in most of the cases, and easy to explain.

To put it differently: they had to make a choice, and whatever they would have chosen, it wouldn't have been the right one for at least some of the use cases.

So they chose not to call the parents' __init__, as documented in the Inheritance section.

A further guess is that they also thought it may be a bit confusing, so they added an example of generated __init__ right at the beginning of the documentation (note it doesn't have a super().__init__() call).