Mypy 不使用 Type[NamedTuple] 进行类型检查
Mypy doesn't typecheck function with Type[NamedTuple]
我有一个函数接受从 NamedTuple
派生的 class 并将其转换为模式。然而,当我 运行 MyPy 在下面的代码上它失败 Argument 1 to "to_schema" has incompatible type "Type[Foo]"; expected "Type[NamedTuple]"
from typing import NamedTuple, Type
def to_schema(named_tuple: Type[NamedTuple]):
pass
class Foo(NamedTuple):
pass
to_schema(Foo)
有没有一种方法可以正确输入代码,以便使用 MyPy 进行类型检查?
编辑:
Python 文档指出 Type[Foo]
接受 Foo
(https://docs.python.org/3/library/typing.html#typing.Type) 的任何子 class。对于我们的数据模型中的实体,我有 NamedTuple
的多个子 classes,所以我正在寻找一种方法来以类型检查的方式注释函数。
您的代码的根本问题是 NamedTuple
不是实际类型——它实际上只是一种特殊类型的 "type constructor",它综合了一个全新的 class 和类型。例如。如果您尝试打印出 Foo.__mro__
的值,您会看到 (<class '__main__.Foo'>, <class 'tuple'>, <class 'object'>)
—— NamedTuple
根本不存在。
这意味着 NamedTuple
实际上根本不是一个有效的类型——在这方面,mypy 只是默默地让你构造 Type[NamedTuple]
开始于.
要解决此问题,您有几种可能的方法:
而不是使用 Type[NamedTuple]
,使用 Type[tuple]
或 Type[Tuple[Any]]
。
你的Foo
毕竟是元组的子类型。
如果您需要专门仅存在于命名元组中的方法或字段,请使用自定义协议。例如,如果你特别需要 namedtuples 中的 _asdict
方法,你可以这样做:
from typing_extensions import Protocol
class NamedTupleProto(Protocol):
def _asdict(self) -> Dict[str, Any]: ...
def to_schema(x: Type[NamedTupleProto]) -> None: pass
class Foo(NamedTuple):
pass
to_schema(Foo)
请注意,您需要安装 typing_extensions
第三方库才能使用它,尽管有计划 formalize Protocols 并将其添加到 Python 中。 (我忘了计划是 Python 3.7 还是 3.8)。
在对 to_schema
的调用中添加类型忽略或强制转换以使 mypy 静音。这不是最好的解决方案,但也是最快的。
相关讨论见this issue。基本上,mypy 团队一致认为有人应该对这个 NamedTuple 事情做些什么,无论是通过添加错误消息还是通过添加官方认可的协议,但我认为人们忙于其他 tasks/bugs 以推动这个前进。 (所以如果你无聊想找点事做...)
我有一个函数接受从 NamedTuple
派生的 class 并将其转换为模式。然而,当我 运行 MyPy 在下面的代码上它失败 Argument 1 to "to_schema" has incompatible type "Type[Foo]"; expected "Type[NamedTuple]"
from typing import NamedTuple, Type
def to_schema(named_tuple: Type[NamedTuple]):
pass
class Foo(NamedTuple):
pass
to_schema(Foo)
有没有一种方法可以正确输入代码,以便使用 MyPy 进行类型检查?
编辑:
Python 文档指出 Type[Foo]
接受 Foo
(https://docs.python.org/3/library/typing.html#typing.Type) 的任何子 class。对于我们的数据模型中的实体,我有 NamedTuple
的多个子 classes,所以我正在寻找一种方法来以类型检查的方式注释函数。
您的代码的根本问题是 NamedTuple
不是实际类型——它实际上只是一种特殊类型的 "type constructor",它综合了一个全新的 class 和类型。例如。如果您尝试打印出 Foo.__mro__
的值,您会看到 (<class '__main__.Foo'>, <class 'tuple'>, <class 'object'>)
—— NamedTuple
根本不存在。
这意味着 NamedTuple
实际上根本不是一个有效的类型——在这方面,mypy 只是默默地让你构造 Type[NamedTuple]
开始于.
要解决此问题,您有几种可能的方法:
而不是使用
Type[NamedTuple]
,使用Type[tuple]
或Type[Tuple[Any]]
。你的
Foo
毕竟是元组的子类型。如果您需要专门仅存在于命名元组中的方法或字段,请使用自定义协议。例如,如果你特别需要 namedtuples 中的
_asdict
方法,你可以这样做:from typing_extensions import Protocol class NamedTupleProto(Protocol): def _asdict(self) -> Dict[str, Any]: ... def to_schema(x: Type[NamedTupleProto]) -> None: pass class Foo(NamedTuple): pass to_schema(Foo)
请注意,您需要安装
typing_extensions
第三方库才能使用它,尽管有计划 formalize Protocols 并将其添加到 Python 中。 (我忘了计划是 Python 3.7 还是 3.8)。在对
to_schema
的调用中添加类型忽略或强制转换以使 mypy 静音。这不是最好的解决方案,但也是最快的。
相关讨论见this issue。基本上,mypy 团队一致认为有人应该对这个 NamedTuple 事情做些什么,无论是通过添加错误消息还是通过添加官方认可的协议,但我认为人们忙于其他 tasks/bugs 以推动这个前进。 (所以如果你无聊想找点事做...)