微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Pydantic - 如何子类化内置类型

如何解决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'>

解决方法

on the doc page of __get_validators__() 所示,您需要产生一个或多个验证器。

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

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)

编辑:没有自定义类和验证器,可以使用函数来编辑要分配给类构造函数的值;需要装饰这个函数,as seen here

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))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。