延迟注解
Note
通过 future import
和 ForwardRef
推迟的注释都需要 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)
(这个脚本是完整的,它应该“按原样”运行)