类型提示引起的循环依赖
有了类型提示,就有更多的机会创建循环导入。幸运的是,有一个使用特殊常量的解决方案: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
带引号和不带引号的类型提示
在3.10之前的Python版本中,必须将有条件导入的类型括在引号中,使它们成为“正向引用”,从而将它们隐藏在解释器运行时中。
在Python 3.7、3.8和3.9中,一种解决方法是使用以下特殊导入。
from __future__ import annotations
这样可以结合使用无引号的类型提示和条件导入。
在Python 3.10中,将不再在定义时评估函数和变量注释。而是将字符串形式保留在相应的注释字典中。静态类型检查器在行为上不会有任何区别,而在运行时使用注释的工具将必须执行推迟的评估。
字符串形式是在编译步骤中从AST获得的,这意味着字符串形式可能不会保留源的确切格式。注意:如果注释已经是字符串文字,则仍将其包装在字符串中。