如何在Mypy中使用__subclasshook__?

问题描述 投票:0回答:2

为什么在 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)

Mypy 是否以特殊方式处理一招小马?

python python-typing mypy structural-typing
2个回答
1
投票

是的,

mypy
将此类类视为特殊情况。请记住,
mypy
用于static类型检查,这意味着它根本不需要运行代码,只需分析源代码即可工作。它实际上从来不会通过 calls
__subclasshook__
或类似的方法来确定什么是可哈希的,什么是不可哈希的。您的“等效”类仅在运行时等效,因为它依赖于被调用。
如果您希望 

__subclasshook__

处理它还不知道的东西,您必须编写一个

mypy 插件
 来处理它。


1
投票
typeshed

包中的规范(“存根文件”)。在这个包中,mypy是一个

collections.abc.Hashable

typeshed/stdlib/_collections_abc.pyi

typing.Protocol

typeshed/stdlib/typing.pyi

from typing import ( AbstractSet as Set, AsyncGenerator as AsyncGenerator, AsyncIterable as AsyncIterable, AsyncIterator as AsyncIterator, Awaitable as Awaitable, ByteString as ByteString, Callable as Callable, Collection as Collection, Container as Container, Coroutine as Coroutine, Generator as Generator, Generic, Hashable as Hashable, ItemsView as ItemsView, Iterable as Iterable, Iterator as Iterator, KeysView as KeysView, Mapping as Mapping, MappingView as MappingView, MutableMapping as MutableMapping, MutableSequence as MutableSequence, MutableSet as MutableSet, Reversible as Reversible, Sequence as Sequence, Sized as Sized, TypeVar, ValuesView as ValuesView, )

	
© www.soinside.com 2019 - 2024. All rights reserved.