由于类型提示而导致的循环依赖
使用类型提示,会有更多机会创建循环导入。幸运的是,可以使用特殊常量typing.TYPE_CHECKING
来解决。
以下示例定义了一个Vertex
类和一个Edge
类。边由两个顶点定义,而顶点维护一个属于它的相邻边的列表。
没有类型提示,没有错误
文件:vertex.py
class Vertex:
def __init__(self, label):
self.label = label
self.adjacency_list = []
文件:edge.py
class Edge:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
类型提示导致ImportError
ImportError: 无法从部分初始化的模块 'edge' 导入 'Edge'(很可能是由于循环导入)
文件:vertex.py
from typing import List
from edge import Edge
class Vertex:
def __init__(self, label: str):
self.label = label
self.adjacency_list: List[Edge] = []
文件:edge.py
from vertex import Vertex
class Edge:
def __init__(self, v1: Vertex, v2: Vertex):
self.v1 = v1
self.v2 = v2
使用TYPE_CHECKING的解决方案
文件:vertex.py
from typing import List, TYPE_CHECKING
if TYPE_CHECKING:
from edge import Edge
class Vertex:
def __init__(self, label: str):
self.label = label
self.adjacency_list: List[Edge] = []
文件:edge.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from vertex import Vertex
class Edge:
def __init__(self, v1: Vertex, v2: Vertex):
self.v1 = v1
self.v2 = v2
请注意类型提示周围的引号的缺失。由于Python 3.10中注解的延迟评估, 这些类型提示被视为在引号中。
带引号与不带引号的类型提示
在Python 3.10之前的版本中,有条件地导入类型必须用引号括起来,使它们成为“前向引用”,这将隐藏它们免受解释器运行时的影响。
在Python 3.7、3.8和3.9中,可以使用以下特殊导入作为解决方法。
from __future__ import annotations
AttributeError
-它使得在sys.modules
中查找部分初始化的模块成为可能,但无法解决时间上的悖论。 - Karl Knechtel