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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51710037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 19:54:35  来源:igfitidea点击:

How should I use the Optional type hint?

pythonpython-3.xtype-hinting

提问by jacobcan118

I'm trying to understand how to use the Optionaltype hint. From PEP-484, I know I can use Optionalfor def test(a: int = None)either as def test(a: Union[int, None])or def test(a: Optional[int]).

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

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

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

回答by Martijn Pieters

Optional[...]is a shorthand notation for Union[..., None], telling the type checker that either an object of the specific type is required, orNoneis 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.

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

So for your two examples, you have dictand listcontainer types, but the default value for the akeyword argument shows that Noneis permitted too so use 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

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

请注意,在技术上使用Optional[]aUnion[]或仅添加NoneUnion[]. 所以Optional[Union[str, int]]Union[str, int, None]是完全一样的东西。

Personally, I'd stick with alwaysusing Optional[]when setting the type for a keyword argument that uses = Noneto set a default value, this documents the reason why Noneis 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.

就个人而言,在设置用于设置默认值的关键字参数的类型时,我会坚持始终使用,这说明了为什么允许更好的原因。此外,它可以更轻松地将部件移动到单独的类型别名中,或者在参数变为必需时稍后删除部件。Optional[]= NoneNoneUnion[...]Optional[...]

For example, say you have

例如,假设你有

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.

    """

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

然后通过将 提取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.

    """

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 Nonevalue is not a 'subwidget id' after all, it's not part of the value, Noneis meant to flag the absence of a value.

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

Side note: You want to avoid using the standard library container types in type hinting however, as you can't say anything about what types they must contain; so instead of dictand list, use typing.Dictand typing.List, respectively. And when only readingfrom a container type, you may just as well accept any immutable abstract container type; lists and tuples are Sequenceobjects, while dictis a Mappingtype:

旁注:然而,您想避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型;因此,而不是dictlist,使用typing.Dicttyping.List分别。当只从容器类型中读取时,您也可以接受任何不可变的抽象容器类型;列表和元组是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