类型提示导致的循环依赖
使用类型提示,创建循环导入的机会更多。幸运的是,有一个使用特殊常量的解决方案: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 中,函数和变量注释将不再是
在定义时进行评估。相反,将保留字符串形式
在各自的 annotations 字典中。静态类型检查器
将看到行为没有差异,而使用注释的工具
运行时将不得不执行延迟评估。
字符串形式是在编译阶段从AST中获取的,
这意味着字符串形式可能不会保留确切的
源的格式。注意:如果注释是字符串文字
已经,它仍然会被包裹在一个字符串中。