Dataclasses act as code generators when working with Objects and Classes in python. It allows us to easily benefit from the dunder methods that are required when creating a class such as __init__,
`__eq__`, etc .
When working with external data sources, however, there may arise situations where additional parameters beyond those explicitly declared in your class definition are provided. In this context, understanding how to handle these “extra” keywords becomes crucial. This is easily achieved in Pydantic, however the Dataclasses package does not support this natively.
Handling Extras in Standard dataclasses
Unfortunately, the standard dataclasses
module does not natively support handling extra keyword arguments. To achieve this, developers often resort to wrapping the __init__
method of their custom dataclass
, which can lead to complex implementations. In this tutorial we will explore a way to allow extra keyword in dataclasses.
In Pydantic we can use the `ConfigDict(allow=”extra”)` to achieve this as shown below
from pydantic import BaseModel, ConfigDict
class BookModel(BaseModel):
name: str
price: float
model: ConfigDict(allow="extra")
bk = BookModel(name="Bible",price="777.0",language="English")
In the above code, you can notice that the `language` field was not defined however because we are allow extra kwargs, we can pass it and use it within our class instance.
Alternatively we can use dataclasses from pydantic to achieve this
from pydantic.dataclasses import dataclass @dataclass(config=dict(extra="allow")) class YourDataClass: field1: str field2: int
To achieve this in Dataclass we can do this
from dataclasses import dataclass
@dataclass
class BookModel:
name:str
price: float
@classmethod
def from_kwargs(cls, **kwargs):
# fetch the constructor's signature
cls_fields = {field for field in signature(cls).parameters}
# split the kwargs into native ones and new ones
native_args, new_args = {}, {}
for name, val in kwargs.items():
if name in cls_fields:
native_args[name] = val
else:
new_args[name] = val
# use the native ones to create the class ...
ret = cls(**native_args)
# ... and add the new ones by hand
for new_name, new_val in new_args.items():
setattr(ret, new_name, new_val)
return ret
We can convert the above classmethod to a decorator and use it
from inspect import signature
def add_from_kwargs(cls):
def from_kwargs(cls, **kwargs):
# fetch the constructor's signature
cls_fields = {field for field in signature(cls).parameters}
# split the kwargs into native ones and new ones
native_args, new_args = {}, {}
for name, val in kwargs.items():
if name in cls_fields:
native_args[name] = val
else:
new_args[name] = val
# use the native ones to create the class ...
ret = cls(**native_args)
# ... and add the new ones by hand
for new_name, new_val in new_args.items():
setattr(ret, new_name, new_val)
return ret
cls.from_kwargs = classmethod(from_kwargs)
return cls
We can then use the decorator for all our dataclasses as below
@add_from_kwargs
@dataclass
class BookModel:
name: str
price: float
In order to allow extra kwargs you will then call the class method eg
params = {'name': 'Book of Paul', 'price': 55.0, 'author': 'Paul', 'year': 1965}
bk = BookModel.from_kwargs(**params)
bk.author
This is one of the ways to add the Pydantic behavior of allowing extra kwargs in dataclasses.
You can check out the video tutorial below
Thanks for your time
Jesus Saves
By Jesse E.Agbe(JCharis)