我应该如何使用 Optional 类型提示? [英] How should I use the Optional type hint?

查看:57
本文介绍了我应该如何使用 Optional 类型提示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解如何使用 Optional 类型提示.从 PEP-484,我知道我可以使用 Optionalcode> for def test(a: int = None) 或者 def test(a: Union[int, None])def test(a: Optional[int]).

I'm trying to understand how to use the Optional type hint. 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]).

但是下面的例子怎么样?

But how about following examples?

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[]有吗?

If Optional[type] seems to mean the same thing as Union[type, None], why should I use Optional[] at all?

推荐答案

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

Optional[...] is a shorthand notation for Union[..., None], telling the type checker that either an object of the specific type is required, or None is required. ... stands for any valid type hint, including complex compound types or a Union[] of more types. Whenever you have a keyword argument with default value None, you should use Optional. (Note: If you are targeting Python 3.10 or newer, PEP 604 introduced a better syntax, see below).

因此,对于您的两个示例,您有 dictlist 容器类型,但是 a 关键字参数的默认值显示 None 也是允许的,所以使用 Optional[...]:

So for your two examples, you have dict and list container types, but the default value for the a keyword argument shows that None is permitted too so use 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

Union[] 上使用 Optional[] 或仅将 None 添加到 Union 在技术上没有区别[].所以 Optional[Union[str, int]]Union[str, int, None] 是完全一样的东西.

There is technically no difference between using Optional[] on a Union[], or just adding None to the Union[]. So Optional[Union[str, int]] and Union[str, int, None] are exactly the same thing.

就我个人而言,在为使用 = None 设置的关键字参数设置类型时,我会坚持 always 使用 Optional[]默认值,这说明了为什么 None 被允许更好的原因.此外,它可以更轻松地将 Union[...] 部分移动到单独的类型别名中,或者稍后删除 Optional[...] 部分,如果参数成为强制性的.

Personally, I'd stick with always using Optional[] when setting the type for a keyword argument that uses = None to set a default value, this documents the reason why None is allowed better. Moreover, it makes it easier to move the Union[...] part into a separate type alias, or to later remove the Optional[...] part if an argument becomes mandatory.

例如,假设您有

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] 提取到类型别名中来改进文档:

then documentation is improved by pulling out the Union[str, int] into a type alias:

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 用于标记值的缺失.

The refactor to move the Union[] into an alias was made all the much easier because Optional[...] was used instead of Union[str, int, None]. The None value is not a 'subwidget id' after all, it's not part of the value, None is meant to flag the absence of a value.

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

Side note: Unless your code only has to support Python 3.9 or newer, you want to avoid using the standard library container types in type hinting, as you can't say anything about what types they must contain. So instead of dict and list, use typing.Dict and typing.List, respectively. And when only reading from a container type, you may just as well accept any immutable abstract container type; lists and tuples are Sequence objects, while dict is a Mapping type:

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 585.但是,虽然你现在可以使用 dict[str, int]list[Union[int, str]]>,您可能仍然希望使用更具表现力的 MappingSequence 注释来指示函数不会改变内容(它们被视为只读"),并且这些函数将分别与任何对象一起用作映射或序列.

In Python 3.9 and up, the standard container types have all been updated to support using them in type hints, see PEP 585. But, 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 that a function won't be mutating the contents (they are treated as 'read only'), and that the functions would work with any object that works as a mapping or sequence, respectively.

Python 3.10 将 | 联合运算符引入类型提示,请参阅 PEP 604.您可以编写 str | 而不是 Union[str, int]整数.与其他类型提示语言一样,在 Python 3.10 及更高版本中表示可选参数的首选(并且更简洁)方式现在是 Type |无,例如<代码>str |无list |无.

Python 3.10 introduces the | union operator into type hinting, see PEP 604. Instead of Union[str, int] you can write str | int. In line with other type-hinted languages, the preferred (and more concise) way to denote an optional argument in Python 3.10 and up, is now Type | None, e.g. str | None or list | None.

这篇关于我应该如何使用 Optional 类型提示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆