ish*_*efi 7 python typing python-3.x python-typing pydantic
Python 3.9 - 我有以下模块:
from __future__ import annotations
from typing import TYPE_CHECKING
from pydantic import BaseModel
if TYPE_CHECKING:
from typing import Optional
class A(BaseModel):
id: int
class Config:
orm_mode = True
class B(A):
foo: C
class C(A):
bar: Optional[str]
C.update_forward_refs()
c = C(id=1, bar='bar')
b = B(id=2, foo=c)
Run Code Online (Sandbox Code Playgroud)
当我导入这个模块时,它会引发NameError: name 'Optional' is not defined. 我可以删除该if TYPE_CHECKING部分,但我知道这是最佳实践(例如,如果我使用自己的类型,则可以防止循环导入)。当我删除B.update_forward_refs()呼叫时,它会引发pydantic.errors.ConfigError: field "foo" not yet prepared so type is still a ForwardRef, you might need to call B.update_forward_refs().
知道如何克服这个问题吗?
正如您所说,TYPE_CHECKING您的示例中不需要,但对于循环导入,您可能需要它。我将举一个更简单的例子来说明如何解决循环导入问题。
我们有以下模块:
foo.py
from typing import TYPE_CHECKING
from pydantic import BaseModel
if TYPE_CHECKING:
from bar import Bar
class Foo(BaseModel):
reference: 'Bar'
Run Code Online (Sandbox Code Playgroud)
酒吧.py
from typing import TYPE_CHECKING, Optional
from pydantic import BaseModel
if TYPE_CHECKING:
from foo import Foo
class Bar(BaseModel):
reference: Optional['Foo']
Run Code Online (Sandbox Code Playgroud)
主要.py
from bar import Bar
from foo import Foo
Bar.update_forward_refs(Foo=Foo)
Foo.update_forward_refs(Bar=Bar)
# Put Bar into Foo and Foo into Bar
Bar(reference=Foo(reference=Bar()))
Run Code Online (Sandbox Code Playgroud)
该解决方案有效(如果我们运行该main.py文件)并且不存在循环导入问题。了解我们如何将FooandBar作为关键字参数传递给update_forward_refs. 这是因为该方法默认使用模型模块的局部变量定义类型,而这些模块空间没有局部变量(正如我们使用的那样if TYPE_CHECKING:)。因此我们自己通过了这些。
如果您正在构建一个包,您可能需要update_forward_refs在__init__.py文件中。