我应该如何使用 Optional 类型提示?

新手上路,请多包涵

我试图了解如何使用 Optional 类型提示。 From PEP-484 , I know I can use Optional for def test(a: int = None) either as def test(a: Union[int, None]) or def test(a: Optional[int]) .

但是下面的例子怎么样?

 def test(a : dict = None):
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a : list = None):
    #print(a) ==> [1,2,3,4, 'a', 'b']
    #or
    #print(a) ==> None

如果 Optional[type] 似乎与 Union[type, None] 意思相同,我为什么要使用 Optional[] 呢?

原文由 jacobcan118 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 990
2 个回答

Optional[...]Union[..., None] 的简写符号,告诉类型检查器需要特定类型的对象, 或者 需要 None ... 代表 _任何有效的类型提示_,包括复杂的复合类型或更多类型的 Union[] 。每当你有一个默认值 None 的关键字参数时,你应该使用 Optional 。 (注意:如果您的目标是 Python 3.10 或更新版本, PEP 604 引入了更好的语法,请参见下文)。

So for your two examples, you have dict and list container types, but the default value for the a keyword argument shows that None 也被允许使用 Optional[...]

 from typing import Optional

def test(a: Optional[dict] = None) -> None:
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a: Optional[list] = None) -> None:
    #print(a) ==> [1, 2, 3, 4, 'a', 'b']
    #or
    #print(a) ==> None

There is technically no difference between using Optional[] on a Union[] , or just adding None to the Union[] .所以 Optional[Union[str, int]]Union[str, int, None] 是完全一样的东西。

就个人而言,我会坚持 始终 使用 Optional[] 为使用 = None 设置默认值的关键字参数设置类型时,这记录了为什么 None 允许更好。此外,它更容易将 Union[...] 部分移动到单独的类型别名中,或者如果参数成为强制性的,则稍后删除 Optional[...] 部分。

例如,假设你有

from typing import Optional, Union

def api_function(optional_argument: Optional[Union[str, int]] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

然后通过将 Union[str, int] 拉出到类型别名中来改进文档:

 from typing import Optional, Union

# subwidget ids used to be integers, now they are strings. Support both.
SubWidgetId = Union[str, int]

def api_function(optional_argument: Optional[SubWidgetId] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

Union[] 移动到别名中的重构变得更加容易,因为使用 Optional[...] 而不是 Union[str, int, None] None 值毕竟不是“subwidget id”,它不是值的一部分, None 是为了标记值的缺失。

旁注:除非您的代码只需要支持 Python 3.9 或更新版本,否则您希望避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型。因此,代替 dict typing.Dict list typing.List 当仅从容器类型 读取 时,您也可以接受任何不可变的抽象容器类型;列表和元组是 Sequence 对象,而 dictMapping 类型:

 from typing import Mapping, Optional, Sequence, Union

def test(a: Optional[Mapping[str, int]] = None) -> None:
    """accepts an optional map with string keys and integer values"""
    # print(a) ==> {'a': 1234}
    # or
    # print(a) ==> None

def test(a: Optional[Sequence[Union[int, str]]] = None) -> None:
    """accepts an optional sequence of integers and strings
    # print(a) ==> [1, 2, 3, 4, 'a', 'b']
    # or
    # print(a) ==> None

在 Python 3.9 及更高版本中,标准容器类型已全部更新以支持在类型提示中使用它们,请参阅 PEP 585But , while you now can use dict[str, int] or list[Union[int, str]] , you still may want to use the more expressive Mapping and Sequence annotations to indicate一个函数不会改变内容(它们被视为“只读”),并且这些函数将分别与 任何 作为映射或序列工作的对象一起工作。

Python 3.10 将 | 联合运算符引入到类型提示中,请参阅 PEP 604 。而不是 Union[str, int] 你可以写 str | int 。与其他类型提示语言一致,在 Python 3.10 及更高版本中表示可选参数的首选(且更简洁)方式现在是 Type | None ,例如 str | Nonelist | None

原文由 Martijn Pieters 发布,翻译遵循 CC BY-SA 4.0 许可协议

直接来自 mypy typing module docs

Optional[str] 只是 Union[str, None] 的简写或别名。它的存在主要是为了方便函数签名看起来更简洁。

Python 3.10+ 的更新

您现在也可以使用管道运算符。

 # Python < 3.10
def get_cars(size: Optional[str]=None):
    pass
# Python 3.10+
def get_cars(size: str|None=None):
    pass

原文由 kevin_theinfinityfund 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题