PydantiC语言 如何子类化一个内置类型



我正在尝试创建timedelta的子类,期望接收毫秒而不是秒,但它目前不工作。

我是不是有点离经叛道?有"权利"吗?如何用Pydantic实现这一点?或者我需要告诉Pydantic,MillisecondTimedelta只是一个timedelta

from datetime import timedelta
from pydantic import BaseModel

class MillisecondTimedelta(timedelta):
@classmethod
def __get_validators__(cls):
# timedelta expects seconds
yield lambda v: v / 1000
yield cls

class MyModel(BaseModel):
td: MillisecondTimedelta
data = {
"td": 7598040,
}
print(MyModel(**data))

结果:

Traceback (most recent call last):
File "main.py", line 14, in <module>
class MyModel(BaseModel):
File "pydantic/main.py", line 262, in pydantic.main.ModelMetaclass.__new__
File "pydantic/fields.py", line 315, in pydantic.fields.ModelField.infer
File "pydantic/fields.py", line 284, in pydantic.fields.ModelField.__init__
File "pydantic/fields.py", line 362, in pydantic.fields.ModelField.prepare
File "pydantic/fields.py", line 541, in pydantic.fields.ModelField.populate_validators
File "pydantic/class_validators.py", line 255, in pydantic.class_validators.prep_validators
File "pydantic/class_validators.py", line 238, in pydantic.class_validators.make_generic_validator
File "/usr/lib/python3.8/inspect.py", line 3105, in signature
return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
File "/usr/lib/python3.8/inspect.py", line 2854, in from_callable
return _signature_from_callable(obj, sigcls=cls,
File "/usr/lib/python3.8/inspect.py", line 2384, in _signature_from_callable
raise ValueError(
ValueError: no signature found for builtin type <class '__main__.MillisecondTimedelta'>

__get_validators__()的文档页面所示,您需要生成一个或多个验证器。

修改后的类报告如下;问题是Pydantic理解int(对于timedelta字段)并浮点为秒(源)。

class MillisecondTimedelta(timedelta):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if any(isinstance(v, t) for t in (int, float)):
return cls(milliseconds=v)

现在一切都正常了。

>>> data = {"td": 1000}
>>> print(MyModel(**data))
td=MillisecondTimedelta(seconds=1)

EDIT:没有自定义类和验证器,可以使用函数编辑要分配给类构造函数的值;需要修饰这个函数,如下所示

class MyModel(BaseModel):
td: timedelta
@validator('td')
def convert_to_ms(cls, v):
return v / 1000

这个解决方案也是有效的:

>>> data = {"td": 3000}
>>> print(MyModel(**data))
td=datetime.timedelta(seconds=3)

啊哈,原来我需要改变两件事。

  1. 实际上从验证器返回timedelta,我返回cls,这是我的自定义子类。

  2. 不要子类化timedelta

from datetime import timedelta
from pydantic import BaseModel

class MillisecondTimedelta:
@classmethod
def __get_validators__(cls):
yield lambda v: timedelta(milliseconds=v)

class MyModel(BaseModel):
td: MillisecondTimedelta

data = {
"td": 7598040,
}
print(repr(MyModel(**data)))
MyModel(td=datetime.timedelta(seconds=7598, microseconds=40000))

相关内容