如何正确地使用变量类型键入注释函数



我正在尝试向与文件系统相关的库添加类型提示,其中许多函数采用strbytes类型的路径。我可以通过使用重载来处理自己的函数,但我很难处理简单的操作或在内部用任何类型的参数调用的标准库函数。下面是一个简化的例子:

@overload
def join_paths(s1: str, s2: str) -> str: ...

@overload
def join_paths(s1: bytes, s2: bytes) -> bytes: ...

def join_paths(s1: Union[str, bytes],
s2: Union[str, bytes]) -> Union[str, bytes]:
return s1 + s2

如果我想从其他地方调用此函数,重载可以正常工作,但我的问题是s1 + s2语句,它会导致mypy发出警告:

example.py:74: error: Unsupported operand types for + ("str" and "bytes")  [operator]
example.py:74: error: Unsupported operand types for + ("bytes" and "str")  [operator]

我想表达的是,要么两个操作数都是str类型,要么都是bytes类型,类似于使用重载对我自己的函数所做的操作。

我在打字方面没有太多经验,所以我可能会错过显而易见的解决方案,但到目前为止,我还没有找到如何调整它来避免警告。

使用TypeVar:

from typing import TypeVar
T = TypeVar('T', str, bytes)

def join_paths(s1: T, s2: T) -> T:
return s1 + s2

join_paths("foo", "bar")    # fine
join_paths(b"foo", b"bar")  # fine
join_paths(1, 2)            # error: T can't be int
join_paths("foo", b"bar")   # error: T can't be object

当不能通过TypeVars和Generics表达类型关系时,重载更像是最后的手段——有效地使用重载通常会在松散类型实现的主体中涉及大量运行时类型断言(或#type: ignores(。

键入.AnyStr最适合这种特定情况。

来自文件:

它用于可以接受任何类型的字符串而不允许混合不同类型的字符串的函数。例如:

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b
concat(u"foo", u"bar")  # Ok, output has type 'unicode'
concat(b"foo", b"bar")  # Ok, output has type 'bytes'
concat(u"foo", b"bar")  # Error, cannot mix unicode and bytes

因此,您可以这样修改您的代码:

from typing import AnyStr

def join_paths(s1: AnyStr, s2: AnyStr) -> AnyStr:
return s1 + s2
join_paths("s1", "s2")  # OK
join_paths(b"s1", b"s2")  # OK
join_paths("s1", b"s2")  # error: Value of type variable "AnyStr" of "join_paths" cannot be "object"

最新更新