I found the issue where was conversation about an explict call of parent's __post_init__
method using super()
, but if I try this:
from dataclasses import dataclass
@dataclass
class A:
def __post_init__(self):
print("A")
@dataclass
class B(A):
pass
b = B()
it will output:
A
So, parents method works without explict call.
- I don't understand what talk about was in this issue or problem with inheritence was solved?
- In which case
__post_init__
method of dataclass doesnt called?
CodePudding user response:
The issue under discussion is in how __init__
and __post_init__
differ.
object
defines __init__
; it doesn't do anything, but that means it's always safe to call super().__init__
in your own definitions of __init__
. You have to take care what arguments you pass to it, but the attribute lookup itself will always succeed.
object
does not define __post_init__
, so calling super().__post_init__
requires you to know whether at least one class in your MRO will define it, or that you check for it first, or you'll get an AttributeError
.
So __post_init__
, if defined, will always be called, but it's not safe to assume for explicit super().__post_init__
calls that the method exists.
CodePudding user response:
By default, the dataclass
decorator generates an __init__
method which does the following (among other things):
- Accepts input arguments based on the field definitions in the current and parent classes
- Initializes the attributes of
self
from input arguments - Calls
self.__post_init__
Python's inheritance works such that if a parent class has an attribute, the child inherits it unless told otherwise. That's sort of the point.
To disable inheritance, you must override it somehow. The pythoic approach to disabling an inherited method entirely is to set it to None
in the child class:
@dataclass
class B(A):
__post_init__ = None
You can find this technique in the documentation of NotImplementedError
, which you should not be using here:
Note: It [
NotImplementedError
] should not be used to indicate that an operator or method is not meant to be supported at all – in that case either leave the operator / method undefined or, if a subclass, set it toNone
.
In fact, any time the child class overrides a method, the parent implementation won't be called unless explicitly told to do so.
In other words, setting the child's method to None
is roughly equivalent to
@dataclass
class B(A):
def __post_init__(self):
pass
While leaving the name out of the child class is very roughly equivalent to
@dataclass
class B(A):
def __post_init__(self):
super().__post_init__()
By not calling super().__post_init__()
from within the child implementation, you prevent the parent implementation from ever being executed.