Python 类型注释:将元组中的项目标记为可选

Python Type Annotations: Mark item in tuple as optional

我有一个函数 returns 一个 2 元组但可选的 3 元组。我如何用类型注释来描述它?

例如:

from typing import Tuple

def example(i):
    # type: (int) -> Tuple[int, int, <what to put here?>]
    if i < 10:
       return (i, i+1, 1)
    else:
       return (i, i+1)

我可以像下面这样使用 Union,但它看起来很乱。

# type: (int) -> Union[Tuple[int, int], Tuple[int, int, int]]

正如评论中所指出的,合并可能是更好的方法。如果签名看起来很乱,你可以这样使用type aliases

from typing import Tuple, Union

MyType = Union[Tuple[int, int], Tuple[int, int, int]]

def example1(i):
    # type: (int) -> MyType
    ...snip...

另一种方法是使用 "indefinite length" Tuple type。您基本上会放弃对元组的确切长度进行编码,但作为交换可以规范化 return 类型并避免该联合。 (如果您的代码 确实 依赖于长度,这可能不是最好的方法)。

def example2(i):
    # type: (int) -> Tuple[int, ...]
    ...snip...

但是,一种更激进的方法是考虑重构您的代码以避免这种情况。

毕竟,如果您要 return 这两种不同的类型,函数的调用者可能无论如何都需要检查长度,对吗?

在那种情况下,一个想法是放弃 return 元组,而是 return NamedTuple 或自定义 class,这两者有一个可选字段。然后,您可以将 "length" 支票转换为 "is this field set to None" 支票。

我想,从某种意义上说,NamedTuple 方法也能以某种方式满足您的原始请求,只要您不介意转换 Tuples/the 增加的开销。

from typing import NamedTuple, Optional

MyType2 = NamedTuple('MyType2', (
    ('x', int),
    ('y', int),
    ('z', Optional[int]),
))

class MyType3(object):
    def __init__(self, x, y, z):
        # type: (int, int, Optional[int]) -> None
        self.x = x
        self.y = y
        self.z = z

(一旦 PEP 557 被接受并集成到语言中,"custom class" 方法可能会更加优雅)。

另一种方法是将您的函数一分为二,如果您提前知道您需要哪种元组的话。然后,您可以调用相应类型的函数。