No project description provided
Project description
Table of Contents
- Table of Contents
Introduction
dataclass alternative with a greater emphasis on the 'class' aspect.
Extract features baozi offers
- Inheritance
- Immutability
- Keyword-only arguments and random order attributes
- Support user-defined
__pre_init__
method that gets executed before class instantiation - Typecasting(experimental)
Installation
pip install baozi
Usage
1. Usage of plain Struct
from baozi import Struct
class Person(Struct, kw_only=True):
age: int = 15
name: str
p = Person(name="baozi")
- Note here that attribute with default value does not have to show before regular attributeo
- You might place dataclass configration directly in class inheritance
- configs will be passed to subclasses
2. Usage of FrozenStruct
baozi is fully compatible with dataclasses.dataclass
from dataclass import is_dataclass
from baozi import FrozenStruct
assert is_dataclass(FrozenStruct)
FrozenStruct is equal to dataclass(frozen=True, slots=True, kw_only=True)
from baozi import FrozenStruct, field
from datetime import datetime
class Event(FrozenStruct):
name: str
create_at: datetime = field(default_factory=datetime.now)
>> e = Event(name="event")
>> assert isinstance(e.created_at, datetime)
>> e.created_at = datetime.now()
dataclasses.FrozenInstanceError: cannot assign to field 'created_at'
Defining FrozenStruct with mutable fields would raise error
since any mutable field would cause failure in immutability of the class
from baozi import FrozenStruct
class Mutable(FrozenStruct):
address: list[str]
baozi.MutableFieldError
Technical Details
config override order
baozi receive config in following order:
- config defined explicitly using //model_config// field defined in the class
- config defined in the inheritance params
- config defined in the parent class of current class
- default config of baozi, which goes like this:
init=True
repr=True
eq=True
order=False
unsafe_hash=False
frozen=False
match_args=True
kw_only=True
slots=False
Struct default: kw_only=True
FrozenStruct defaults: kw_only=True frozen=True slots=True
Rationale of existence
why wouldn't I just use dataclass?
Mostly because of the decorator approach, dataclass uses decorators for transforming a regular class into a dataclass, and when I use dataclass in production, I soon realize that:
-
Code repetition, when there are tons of dataclasses, you are going to decorate them with
@dataclass
over and over again -
Error-prone, for non-trivial application, you often have different configuration of dataclass, like
@dataclass(frozen)
, if you inherit from a frozen dataclass and you use regular@dataclass
decorator, odds are you are going to have a bad time. -
It simply does not make sense to use decorator, when you decorating a class, it implies that your class would work just fine without the decorator, and that is not the case, if you get rid of the
@dataclass
decorator, your class won't work.
why wouldn't I just use pydantic.BaseModel?
Mostly because of You don't need validation, and you can use both.
pydantic is very powerful and strong and I use it in various projects, but there are certain scenarios where I find pydantic to be an overkill.
-
Data are already validated in the API layer, and once the input goes through API and penetrate into my application layer, i know those data are safe, cause they are generated by my code.
-
performance, despite how performant pydantic is, depending on complexity, it is ususally 5x to 100x times slower than a dataclass, which is essentially a regular python class. baozi also support usage of slots, which effciently cut about 1/3 of memory usage comparing to regular python class.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.