I want to create a class hierarchy, where all objects of class Base
has a field field1
, but different subclasses have different default values for field1
. The classes are data holders, so dataclasses
seems like the perfect library to use.
Consider the following python 3.7+ code.
from dataclasses import dataclass, field
from typing import Any, Iterable
@dataclass
class Base:
field1: Iterable[Any]
@dataclass
class Sub(Base):
field2: Any
field1: Iterable[Any] = field(default_factory=list)
The code fails, giving me TypeError: non-default argument 'field2' follows default argument
. This is a little surprising, since field2
follows the non-default field1
of the superclass, and the defalt argument field1
of the class Sub
actually comes after field2
.
According to the example in the docs on dataclass inheritence though, fields in subclasses overrides the fields in superclasses, but field order is preserved. So the error makes sense.
Is there any suitable workaround here, or must I implement everything by hand?
Inheriting a data class from another data class is not allowed because there is no way to make compiler-generated data class methods work consistently and intuitively in case of inheritance. yole: You can inherit a data class from a non-data class.
dataclasses has a special method called __post_init__ . As the name clearly suggests, this method is called right after the __init__ method is called. Going back to the previous example, we can see how this method can be called to initialize an internal attribute that depends on previously set attributes.
Defining a data class. A Python class is a program used to create objects and their properties. We use the keyword class to create a class in Python. For class attributes to be initialized, we use a constructor method called __init__() which is called when an object is created in a Python class.
When you use Python inheritance to create dataclasses, you cannot guarantee that all fields with default values will appear after all fields without default values. An easy solution is to avoid using multiple inheritance to construct a "merged" dataclass.
You can use the @property decorator:
from dataclasses import dataclass
from typing import Any, Iterable
@dataclass
class Base:
@property
def field1(self) -> Iterable[Any]:
return
@dataclass
class Sub(Base):
field2: Any
@property
def field1(self) -> Iterable[Any]:
return [] # or whatever default you want to put here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With