以下代码:
def foo(bar: dict[int | float, int | float]) -> None:
pass
foo({1: 1})
bas = {1: 1}
foo(bas)
触发以下 mypy 错误:
6: error: Argument 1 to "foo" has incompatible type "dict[int, int]"; expected "dict[int | float, int | float]" [arg-type]
我在函数
Table.replace_schema_metadata
中使用 pyarrow 遇到了这个错误。
错误出现在第 6 行而不是第 4 行:即使用文字就可以了, 但与变量的值不同。为什么?
为什么
dict[int, int]
与dict[int | float, int | float]
不兼容?
我可以做什么来解决这个错误(除了
# type: ignore[arg-type]
)?
使用Python 3.11.3和mypy 1.9.0。
这里需要理解的重要一点是 MyPy 如何进行类型推断。由于您没有指定函数签名以外的变量类型,因此 MyPy 必须“猜测”其他变量的类型。 MyPy 文档
中甚至描述了这种确切的情况声明的参数类型也用于类型上下文。在此程序中,mypy 知道空列表
应该具有类型[]
,基于list[int]
中声明的arg
类型:foo
def foo(arg: list[int]) -> None:
print('Items:', ''.join(str(a) for a in arg))
foo([]) # OK
最相关的部分:
但是,上下文仅适用于单个语句。这里 mypy 需要对空列表进行注释,因为上下文仅在以下语句中可用:
def foo(arg: list[int]) -> None:
print('Items:', ', '.join(arg))
a = [] # Error: Need type annotation for "a"
foo(a)
解决方案 - 为变量添加类型注释:
a: list[int] = [] # OK
foo(a)
或者,就您而言:
bas: dict[int|float, int|float] = {1: 1}
如果你想避免每次都使用冗长的类型,你可以创建一个别名:
type numberDict = dict[int|float, int|float]
def foo(bar: numberDict) -> None:
pass
foo({1: 1})
bas: numberDict = {1: 1}
foo(bas)