我有一个Python类
MyClass
,有三种可接受的方法来实例化它:
BitVector
;int
和 bytes
表示位向量的大小和内容;int
和 str
表示位向量的大小和内容。使用类型注释,特别是
@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, *, size: int, 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
声明的类型约束...
如何对参数可以采用的唯一类型组合(如
@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 中添加了 * 以遵循重载签名。