跳转至

Pydantic Company

我们根据我认为导致 Pydantic 成功的原则创办了一家公司。

公司公告中了解更多信息.

延迟注解

Note

通过 future importForwardRef 推迟的注释都需要 Python 3.7+。

延时注解(如 PEP563 中所述)“正常工作”。

from __future__ import annotations
from typing import Any, List
from pydantic import BaseModel


class Model(BaseModel):
    a: List[int]
    b: Any


print(Model(a=('1', 2, 3), b='ok'))
#> a=[1, 2, 3] b='ok'
from __future__ import annotations
from typing import Any
from pydantic import BaseModel


class Model(BaseModel):
    a: list[int]
    b: Any


print(Model(a=('1', 2, 3), b='ok'))
#> a=[1, 2, 3] b='ok'

(这个脚本是完整的,它应该“按原样”运行)

在内部,pydantic 将调用类似于typing.get_type_hints的方法来解析注释。

在尚未定义引用类型的情况下,可以使用ForwardRef(尽管在 自引用模型 的情况下,直接引用类型或通过其字符串引用是一种更简单的解决方案) .

在某些情况下,ForwardRef在模型创建期间将无法解析。 例如,只要模型将自身引用为字段类型,就会发生这种情况。 发生这种情况时,您需要在创建模型后调用 update_forward_refs 才能使用它:

from typing import ForwardRef
from pydantic import BaseModel

Foo = ForwardRef('Foo')


class Foo(BaseModel):
    a: int = 123
    b: Foo = None


Foo.update_forward_refs()

print(Foo())
#> a=123 b=None
print(Foo(b={'a': '321'}))
#> a=123 b=Foo(a=321, b=None)

(这个脚本是完整的,它应该“按原样”运行)

Warning

要将字符串(类型名称)解析为注释(类型),pydantic 需要一个名称空间字典来执行查找。 为此,它使用 module.__dict__ ,就像 get_type_hints 一样。

这意味着 pydantic 可能无法很好地处理未在模块全局范围内定义的类型。

例如,这个可以正常工作:

from __future__ import annotations
from pydantic import BaseModel
from pydantic import HttpUrl  # HttpUrl is defined in the module's global scope


def this_works():
    class Model(BaseModel):
        a: HttpUrl

    print(Model(a='https://example.com'))
    #> a=HttpUrl('https://example.com', )


this_works()

(这个脚本是完整的,它应该“按原样”运行)

但这个就会中断:

from __future__ import annotations
from pydantic import BaseModel
from pydantic.errors import ConfigError


def this_is_broken():
    from pydantic import HttpUrl  # HttpUrl is defined in function local scope

    class Model(BaseModel):
        a: HttpUrl

    try:
        Model(a='https://example.com')
    except ConfigError as e:
        print(e)
        #> field "a" not yet prepared so type is still a ForwardRef, you might
        #> need to call Model.update_forward_refs().

    try:
        Model.update_forward_refs()
    except NameError as e:
        print(e)
        #> name 'HttpUrl' is not defined


this_is_broken()

(这个脚本是完整的,它应该“按原样”运行)

解决这个问题超出了对 pydantic 的调用:要么删除未来的导入,要么在全局范围内声明类型。

自引用模型(Self-referencing Models)

还支持具有自引用模型的数据结构。 自引用字段将在模型创建后自动解析。

在模型中,您可以使用字符串引用尚未构建的模型:

from pydantic import BaseModel


class Foo(BaseModel):
    a: int = 123
    #: The sibling of `Foo` is referenced by string
    sibling: 'Foo' = None


print(Foo())
#> a=123 sibling=None
print(Foo(sibling={'a': '321'}))
#> a=123 sibling=Foo(a=321, sibling=None)

(这个脚本是完整的,它应该“按原样”运行)

从 Python 3.7 开始,你也可以通过它的类型来引用它,前提是你导入了annotations(参见 上面 以获得依赖于 Python 和 pydantic 版本的支持)。

from __future__ import annotations
from pydantic import BaseModel


class Foo(BaseModel):
    a: int = 123
    #: The sibling of `Foo` is referenced directly by type
    sibling: Foo = None


print(Foo())
#> a=123 sibling=None
print(Foo(sibling={'a': '321'}))
#> a=123 sibling=Foo(a=321, sibling=None)

(这个脚本是完整的,它应该“按原样”运行)