13
votes

What are the advantages and disadvantages of using Pydantic's dataclass vs BaseModel? Are there any performance issues or is it easier to Pydantic's dataclass in the other python module?

2
I've implemented the validation of pure dataclasses: github.com/EvgeniyBurdin/validated_dcEvgeniy_Burdin

2 Answers

10
votes

Your question is answered in Pydantic's documentation, specifically:

Keep in mind that pydantic.dataclasses.dataclass is a drop-in replacement for dataclasses.dataclass with validation, not a replacement for pydantic.BaseModel (with a small difference in how initialization hooks work). There are cases where subclassing pydantic.BaseModel is the better choice.

For more information and discussion see samuelcolvin/pydantic#710.

The discussion link will give you some of the context you are looking for. In general, Pydantic's BaseModel implementation is not bound to behave the same as Python's dataclass implementation. The example cited in the issue above is one good example:

from pydantic import BaseModel
from pydantic.dataclasses import dataclass
from typing import List

@dataclass
class A:
    x: List[int] = []

# Above definition with a default of `[]` will result in:
#   ValueError: mutable default <class 'list'> for field x is not allowed: use default_factory
# If you resolve this, the output will read as in the comments below.

class B(BaseModel):
    x: List[int] = []

print(A(x=[1, 2]), A(x=[3, 4])) # Output: A(x=[1, 2]) A(x=[3, 4])
print(B(x=[1, 2]), B(x=[3, 4])) # Output: x=[1, 2] x=[3, 4]

If what you want first and foremost is dataclass behavior and then to simply augment it with some Pydantic validation features, the pydantic.dataclasses.dataclass approach may be what you want. Otherwise, BaseModel is probably what you want.

3
votes

The init Function for BaseModel works differently than the init for dataclass

@dataclass()
class Foo:
    number: int

class Bar(BaseModel):
    number: int

f = Foo(number = 1.4)
b = Bar(number = 1.4)
print(f)
print(b)

Output:

Foo(number=1.4)
number=1