【问题标题】:How to correctly type-annotate functions with variable types?如何正确地对具有变量类型的函数进行类型注释?
【发布时间】:2021-08-16 00:23:08
【问题描述】:

我正在尝试向文件系统相关库添加类型提示,其中许多函数采用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 类型,类似于使用重载对我自己的函数所做的。

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

【问题讨论】:

  • 查看link
  • 谢谢,@gowridev!

标签: python python-typing


【解决方案1】:

使用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 和泛型表达类型关系时,重载更像是一种不得已的工具——有效地使用重载通常会在松散的主体中涉及大量运行时类型断言(或 #type: ignores) -类型化的实现。

【讨论】:

  • 非常感谢!我知道我一定忽略了一些东西 - 结果我误解了TypeVar
  • 你也可以使用AnyStr
  • 谢谢,@PaulLemarchand - 我没见过这个。这对这种特定情况非常有帮助,您可能会将其添加为另一个答案!
【解决方案2】:

typing.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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 2020-09-01
    相关资源
    最近更新 更多