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

jac*_*118 20 python type-hinting python-3.x

我试图了解如何使用Optional类型提示.从PEP 434,我知道我可以使用Optionaldef test(a: int = None)无论是作为def test(a: Union[int, None])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
Run Code Online (Sandbox Code Playgroud)

Optional[type]似乎意味着同样的事情Union[type, None],我为什么要使用它Optional[]

Mar*_*ers 29

Optional[...]是一种简写符号Union[..., None],告诉类型检查器需要特定类型的对象,或者 None是必需的....代表任何有效的类型提示,包括复杂的复合类型或Union[]更多类型.每当你有一个带有默认值的关键字参数时None,你应该使用Optional.

因此,对于您的两个示例,您有dictlist容器类型,但a关键字参数的默认值显示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
Run Code Online (Sandbox Code Playgroud)

请注意,在使用Optional[]a Union[]或仅添加None到技术上没有区别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.

    """
Run Code Online (Sandbox Code Playgroud)

然后通过拉出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.

    """
Run Code Online (Sandbox Code Playgroud)

移动Union[]到别名的重构变得更容易,因为Optional[...]使用而不是Union[str, int, None].None毕竟,该值不是'子窗口小部件ID',它不是值的一部分,None旨在标记缺少值.

附注:您希望避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型; 所以代替dictlist,使用typing.Listtyping.Dict.当只从容器类型中读取时,您也可以接受任何不可变的抽象容器类型; 列表和元组Sequence对象,同时dict是一个Mapping类型:

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
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,当 Python 3.10 中引入新类型联合运算符([PEP 604](https://www.python.org/dev/peps/pep-0604/))时,首选方式将回到` Union[str, int, None]`,现在以一种新的奇特方式编写为“str | 整数 | None`,无需导入输入模块。 (8认同)
  • @quant_dev:恶心,马吕斯是正确的。“Optional”仅意味着参数可以默认为“None”,而不是可以省略。我的错。 (4认同)
  • @user48956:我添加了关于 3.9 的部分。 (3认同)
  • 如果添加“from __future__ import 注解”,则可以在 Python 3.7+ 上使用“dict[X]”和“list[X]”。 (2认同)
  • @MartijnPieters 这不是重点。关键是可选并不意味着你所说的意思。 (2认同)
  • @MartijnPieters 事实上 quant_dev 是对的,“可选”并不明确意味着该参数是可选的,请参阅 PEP-484 或 https://docs.python.org/3/library/typing.html#typing.Optional。你可以抱怨这是用词不当,但事实就是如此。 (2认同)

Mic*_*ura 15

请注意,从 Python 3.10 开始,您可以简化代码并键入:

def foo(
   bar: int | None = None,
   another_bar: Callable[[int, list, float, datetime | None], str],
):
Run Code Online (Sandbox Code Playgroud)


Tro*_*roy 14

虽然接受的答案是正确的答案,但需要注意的另一件事是,在 的上下文中kwargs, 和Optional[...]都是Union[..., None]多余且不必要的。如果您立即将 kwarg 设置为None,那么 IDEmypy和 IDE 都会假定显而易见的情况并自动将 arg 视为Optional[...]

集成开发环境:

在此输入图像描述

我的:

mypy 自动 可选

然而,对于变量和方法/函数返回值,Optional[...]仍然是必要的,因为mypy在这些情况下无法知道自动假设任何内容。

  • 确实如此,但[不推荐](https://peps.python.org/pep-0484/#union-types)。 (5认同)

kev*_*und 12

直接来自mypy 输入模块文档

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

  • 它应该被称为“Nullable”。“可选”是相当误导的。 (25认同)
  • 同意。它实际上与默认参数无关,许多人认为默认参数是“可选的”。我认为这是很多混乱的根源。 (6认同)