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

时间:2018-08-06 14:33:53

标签: python python-3.x type-hinting

我试图了解如何使用Optional类型提示。从PEP 434中,我知道可以将Optional的{​​{1}}用作def 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 的含义似乎与Optional[type]相同,为什么我应该完全使用Union[type, None]

4 个答案:

答案 0 :(得分:10)

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

请注意,在Optional[]上使用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.

    """

然后通过将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旨在标记不存在值。

侧面说明:但是,您要避免在类型提示中使用标准库容器类型,因为您不能说出它们必须包含什么类型;因此,请使用dictlist代替typing.Listtyping.Dict。而且,当只从容器类型中读取时,您也可以接受任何不可变的抽象容器类型。列表和元组是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[List[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

答案 1 :(得分:4)

直接来自mypy typing module docs

  • “ Optional [str]只是Union [str,None]的简写或别名。它主要是为方便功能签名看起来更简洁而提供的。”

答案 2 :(得分:2)

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

集成开发环境:

enter image description here

我的:

mypy automatic Optional

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

答案 3 :(得分:0)

直到 Python 3.9,如果你想提示一个 nullable 值,你有两个选择:

import typing

def foo(bar: typing.Optional[str]):
    ....

def foo(bar: typing.Union[str, None]):
    ....

从 Python 3.9 开始,您不需要使用输入模块:

def foo(bar: str = None):
    ....