如何与mypy一起使用__subclasshook__?
为什么在 Mypy 下,__subclasshook__
适用于来自 collections.abc
的一招小马,但不适用于用户定义的类?
例如,这个程序
from collections.abc import Hashable
class A:
def __hash__(self) -> int:
return 0
a: Hashable = A()
输出
$ mypy demo.py --strict
Success: no issues found in 1 source file
但是这个等效程序
from abc import ABCMeta, abstractmethod
def _check_methods(C: type, *methods: str) -> bool:
mro = C.__mro__
for method in methods:
for B in mro:
if method in B.__dict__:
if B.__dict__[method] is None:
return NotImplemented
break
else:
return NotImplemented
return True
class Hashable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __hash__(self) -> int:
return 0
@classmethod
def __subclasshook__(cls, C: type) -> bool:
if cls is Hashable:
return _check_methods(C, "__hash__")
return NotImplemented
class A:
def __hash__(self) -> int:
return 0
a: Hashable = A()
输出
$ mypy demo.py --strict
demo.py:32: error: Incompatible types in assignment (expression has type "A", variable has type "Hashable")
Found 1 error in 1 file (checked 1 source file)
Does Mypy handle one-trick pony in aspecial way?
How come that under Mypy, __subclasshook__
works for one-trick ponies from collections.abc
, but not for user-defined classes?
For instance, this program
from collections.abc import Hashable
class A:
def __hash__(self) -> int:
return 0
a: Hashable = A()
outputs
$ mypy demo.py --strict
Success: no issues found in 1 source file
But this equivalent program
from abc import ABCMeta, abstractmethod
def _check_methods(C: type, *methods: str) -> bool:
mro = C.__mro__
for method in methods:
for B in mro:
if method in B.__dict__:
if B.__dict__[method] is None:
return NotImplemented
break
else:
return NotImplemented
return True
class Hashable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __hash__(self) -> int:
return 0
@classmethod
def __subclasshook__(cls, C: type) -> bool:
if cls is Hashable:
return _check_methods(C, "__hash__")
return NotImplemented
class A:
def __hash__(self) -> int:
return 0
a: Hashable = A()
outputs
$ mypy demo.py --strict
demo.py:32: error: Incompatible types in assignment (expression has type "A", variable has type "Hashable")
Found 1 error in 1 file (checked 1 source file)
Does Mypy handle one-trick ponies in a special way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
mypy不使用标准库的实现,而是使用 typeshed collections.abc.hashable 是
typing.protocol
。typeshed/stdlib/stdlib/typ.pyi.pyi.pyi :pyi :
Mypy does not use the implementations of the standard library but its specifications (’stub files’) from the typeshed package. In this package,
collections.abc.Hashable
is atyping.Protocol
.typeshed/stdlib/_collections_abc.pyi:
typeshed/stdlib/typing.pyi:
是的,
mypy
将这些类别视为特殊情况。请记住,mypy
适用于 static 类型检查,这意味着它根本不运行代码,只能分析源代码。它从来没有真正呼叫__ subclasshook __
或可以确定什么是不可悬浮的内容。您的“等效”类仅在运行时等效,因为它依赖于__ subclasshook __
被调用。如果您想要
mypy
与它尚不了解的东西一起工作,则必须编写mypy
插件处理它。Yes,
mypy
treats these kind of classes as special cases. Remember,mypy
is for static type checking, which means it works without running your code at all, only analyzing the source code. It never actually calls__subclasshook__
or the like to determine what is or isn't hashable. Your "equivalent" class is only equivalent at runtime, as it relies on__subclasshook__
being called.If you want
mypy
to work with something it doesn't already know about, you would have to write amypy
plugin to handle it.