Package: baozi
Table of ContentsTable of ContentsIntroductionExtract features baozi offersInstallationUsage1. Usage of plain Structpre_init hook2. Usage of FrozenStructbaozi is fully compatible with dataclasses.dataclassFrozenStruct is equal to dataclass(frozen=True, slots=True, kw_only=True)Defining FrozenStruct with mutable fields would raise errorTechnical Detailsconfig override orderRationale of existencewhy wouldn't I just use dataclass?why wouldn't I just use pydantic.BaseModel?Introductiondataclass alternative with a greater emphasis on the 'class' aspect.Extract features baozi offersInheritanceImmutabilityKeyword-only arguments and random order attributesSupport user-defined__pre_init__method that gets executed before class instantiationTypecasting(experimental)InstallationpipinstallbaoziUsage1. Usage of plain StructfrombaoziimportStructclassPerson(Struct,kw_only=True):age:int=15name:strp=Person(name="baozi")pre_init hookclassB(baozi.Struct):name:strage:int@classmethoddef__pre_init__(cls,**data):data["age"]=int(data["age"])returndataassertasdict(B(name="name",age="15"))=={"name":"name","age":15}Note here that attribute with default value does not have to show before regular attributeoYou might place dataclass configration directly in class inheritanceconfigs will be passed to subclassesconfig class meta by passing class arguments or defining__model_config__field in the class2. Usage of FrozenStructbaozi is fully compatible with dataclasses.dataclassfromdataclassimportis_dataclassfrombaoziimportFrozenStructassertis_dataclass(FrozenStruct)FrozenStruct is equal to dataclass(frozen=True, slots=True, kw_only=True)frombaoziimportFrozenStruct,fieldfromdatetimeimportdatetimeclassEvent(FrozenStruct):name:strcreate_at:datetime=field(default_factory=datetime.now)>>e=Event(name="event")>>assertisinstance(e.created_at,datetime)>>e.created_at=datetime.now()dataclasses.FrozenInstanceError:cannotassigntofield'created_at'Defining FrozenStruct with mutable fields would raise errorsince any mutable field would cause failure in immutability of the classfrombaoziimportFrozenStructclassMutable(FrozenStruct):address:list[str]baozi.MutableFieldErrorTechnical Detailsconfig override orderbaozi receive config in following order:config defined explicitly using__model_config__field defined in the classconfig defined in the inheritance paramsconfig defined in the parent class of current classdefault config of baozi, which goes like this:init=Truerepr=Trueeq=Trueorder=Falseunsafe_hash=Falsefrozen=Falsematch_args=Truekw_only=Trueslots=FalseStruct default:
kw_only=TrueFrozenStruct defaults:
kw_only=True
frozen=True
slots=TrueRationale of existencewhy wouldn't I just use dataclass?Mostly because ofthe decoratorapproach, 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@dataclassover and over againError-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@dataclassdecorator, 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@dataclassdecorator, your class won't work.why wouldn't I just use pydantic.BaseModel?Mostly because ofYou 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 validatedin 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 is constantly faster than pydantic, especially for model with complex validation logic(since baozi does not validate by default),  baozi also support usage of slots, which effciently cut about 1/3 of memory usage comparing to regular python class.