4 ms·
Dataclasses are nice but they have a big downside: extending a dataclass with a default property can raise an error. If you run this code: import dataclas
by goodoldneon 4y ago
Dataclasses are nice but they have a big downside: extending a dataclass with a default property can raise an error.
If you run this code:
import dataclasses
@dataclasses.dataclass
class Base:
a: int
b: int = 1
@dataclasses.dataclass
class Child(Base):
c: int
Then you'll get this error:
TypeError: non-default argument 'c' follows default argument
- zzzeek 4y agothat's because you are expecting dataclasses to create a default `__init__()` for you, which it can't do with that declaration. set init=False if you don't want it to do that. import dataclasses @dataclasses.dataclass class Base: a: int b: int = 1 @dataclasses.dataclass(init=False) class Child(Base): c: int if you want the init to be generated for you, you have to tell it how, given that "b" has a default value. so "c" needs to be keyword only here: import dataclasses @dataclasses.dataclass class Base: a: int b: int = 1 @dataclasses.dataclass class Child(Base): _: dataclasses.KW_ONLY c: int
- goodoldneon 4y agoLooks like that works but it’s unintuitive. Pydantic can handle this situation without the weird KW_ONLY thing, so dataclasses should too
- zzzeek 4y agohm it implicitly decides to be KW_ONLY? OK does not work: from pydantic import dataclasses @dataclasses.dataclass class Base: a: int b: int = 1 @dataclasses.dataclass class Child(Base): c: int error File "pydantic/dataclasses.py", line 265, in pydantic.dataclasses.dataclass ... File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 539, in _init_fn raise TypeError(f'non-default argument {f.name!r} ' TypeError: non-default argument 'c' follows default argument it works with KW_ONLY though awkward that pydantic.dataclasses doesn't supply it directly, need to split up imports among pydantic.dataclasses and dataclasses.
- goodoldneon 4y agoExtend from pydantic.BaseModel instead of using the dataclasses decorator
- zzzeek 4y agonot SQLAlchemy compatible, interest lost :)
- goodoldneon 4y agoI didn’t mean “always use Pydantic instead of dataclasses”. I meant “dataclasses have a default property problem but it’s solvable since Pydantic handles them well”
- saiojd 4y agoI personally just use `dataclass(kw_only=True)`, which should really be the default in most cases anyways.
- conaclos 4y agoI think the same. `slots=True` should also be the default.
- goodoldneon 4y agoNice, I think kw_only=True and slots=True solve a lot of my dataclass problems. Wish they defaulted to true
- conaclos 4y ago`frozen=True` is really nice also if your data does not change :)
- dragonwriter 4y ago> Nice, I think kw_only=True and slots=True solve a lot of my dataclass problems. Wish they defaulted to true While it doesn’t solve reading other people’s code with the defaults you’d like to have, dataclass being a decorator and not a special syntax means that you can just derive a new decorator from it with the defaults you want.
- conaclos 4y ago> you can just derive a new decorator from it with the defaults you want. This could hurt basic static analysis.
- dragonwriter 4y ago> This could hurt basic static analysis. That’s a good point. I know some of the python static analysis tools can “see through” some simple indirection, but don't know if even a simple wrapper injecting arguments would work with any (or which) of them for this purpose.