问题描述
我有一个 Python 类 MyClass
,有三种可接受的方式来实例化它:
使用类型注释,特别是 @overload
装饰器,我确保构造函数不会被滥用。
最重要的是,为了确保我不会忘记任何情况,我实施了详尽的模式匹配。
总的来说,它看起来如下:
from typing import overload,noreturn,Optional,Union
def assert_never(value: noreturn) -> noreturn:
assert False,f'Unhandled value: {value} ({type(value).__name__})'
class BitVector(): ...
class MyClass:
@overload
def __init__(self,*,size: int,content: bytes): ...
@overload
def __init__(self,content: int): ...
@overload
def __init__(self,bv: BitVector): ...
def __init__(self,bv: Optional[BitVector]=None,size: Optional[int]=None,content: Optional[Union[bytes,int]]=None):
if isinstance(size,int) and isinstance(content,(bytes,int)):
# instanciate a BitVector and do something
...
elif isinstance(bv,BitVector):
# do something with it
...
else:
assert_never((bv,size,content))
但是,在运行 mypy
时,出现以下错误:
example.py:25: error: Argument 1 to "assert_never" has incompatible type "Tuple[None,Optional[int],Union[bytes,int,None]]"; expected "noreturn"
Found 1 error in 1 file (checked 1 source file)
就好像mypy
只依赖实现函数的签名,没有考虑@overload
s声明的类型约束...
如何对 @overload
声明所声明的参数可以采用的唯一类型组合执行详尽的模式匹配?
解决方法
你不应该给真正的 def 函数添加签名:
@overload
def __init__(self,*,size: int,content: Union[bytes,int]): ...
@overload
def __init__(self,bv: BitVector): ...
def __init__(self,bv=None,size=None,content=None):
我在真正的 def 中添加了 * 以遵循重载签名。