尝试构建递归类型来注释嵌套数据结构,我点击了以下内容。
根据mypy,此代码是正确的:
IntType = int | list["IntType"] | tuple["IntType", ...]
StrType = str | list["StrType"] | tuple["StrType", ...]
def int2str(x: IntType) -> StrType:
if isinstance(x, list):
return list(int2str(v) for v in x)
if isinstance(x, tuple):
return tuple(int2str(v) for v in x)
return str(x)
但不是这个,它应该是等效的:
IntType = int | list["IntType"] | tuple["IntType", ...]
StrType = str | list["StrType"] | tuple["StrType", ...]
def bad_int2str(x: IntType) -> StrType:
if isinstance(x, (list, tuple)):
return type(x)(bad_int2str(v) for v in x) # error here
return str(x)
错误信息是
line 6: error: Incompatible return value type (
got "list[int | list[IntType] | tuple[IntType, ...]] | tuple[int | list[IntType] | tuple[IntType, ...], ...]",
expected "str | list[StrType] | tuple[StrType, ...]"
) [return-value]
line 6: error: Generator has incompatible item type
"str | list[StrType] | tuple[StrType, ...]";
expected "int | list[IntType] | tuple[IntType, ...]" [misc]
我假设 mypy 可以推断
type(x)
是 list
或 tuple
。
这是 mypy 的限制还是这段代码有问题?
如果是这样,限制来自哪里?
Mypy 是一个静态类型检查器,这意味着它在运行时不会评估
type(x)(bad_int2str(v) for v in x)
。所以 Mypy 不可能知道表达式的类型是 StrType
。
您可以像下面的例子一样给出提示。
def good_int2str(x: IntType) -> StrType:
if isinstance(x, (list, tuple)):
ty: type[list | tuple] = type(x)
return ty(good_int2str(v) for v in x)
return str(x)
def another_good_int2str(x: IntType) -> StrType:
if isinstance(x, (list, tuple)):
return cast(type[list | tuple], type(x))(
another_good_int2str(v) for v in x)
return str(x)