簡體   English   中英

Pydantic - 如何子類化內置類型

[英]Pydantic - How to subclass a builtin type

我正在嘗試創建一個期望接收毫秒而不是秒的 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__()的文檔頁面所示,您需要生成一個或多個驗證器。

修改后的 class 報道如下; 問題是 Pydantic 理解(對於 timedelta 字段) int 並浮動為 seconds(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)

編輯:如果沒有自定義 class 和驗證器,可以使用 function 編輯要分配給 class 構造函數的值; 需要裝飾這個 function,如圖所示

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM