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

Python 我应该如何使用可选类型提示?,python,python-3.x,type-hinting,Python,Python 3.x,Type Hinting,我试图理解如何使用可选的类型提示。从中,我知道我可以使用Optional进行def测试(a:int=None)作为def测试(a:Union[int,None])或def测试(a:Optional[int]) 但是下面的例子怎么样 def test(a : dict = None): #print(a) ==> {'a': 1234} #or #print(a) ==> None def test(a : list = None): #print(a

我试图理解如何使用
可选的
类型提示。从中,我知道我可以使用
Optional
进行
def测试(a:int=None)
作为
def测试(a:Union[int,None])
def测试(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[]

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

因此,对于您的两个示例,您有
dict
list
容器类型,但是
a
关键字参数的默认值显示也允许
None
,因此使用
可选[…]

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]
是完全一样的

就我个人而言,在设置关键字参数的类型时,如果使用
=None
来设置默认值,我会坚持始终使用
Optional[]
,这说明了允许使用
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.

    """
然后,通过将
联合[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
值毕竟不是“子窗口小部件id”,它不是值的一部分,
None
用于标记没有值

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

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
在Python3.9及更高版本中,标准容器类型都已更新,以支持在类型提示中使用它们,请参阅。但是,虽然您现在可以使用
dict[str,int]
list[Union[int,str]]
,但您可能仍然希望使用更具表达力的
映射
序列
注释来指示函数不会对内容进行变异(它们被视为“只读”),这些函数将分别与作为映射或序列的任何对象一起工作

Python 3.10将
|
联合运算符引入类型暗示,请参阅。您可以编写
str | int
,而不是
Union[str,int]
。与其他类型提示语言一样,在Python 3.10及更高版本中,表示可选参数的首选(更简洁)方法是现在直接从中使用
type | None
,例如
str | None
list | None

  • 可选[str]只是联合[str,None]的简写或别名。它的存在主要是为了方便函数签名看起来更干净

虽然公认的答案是正确的,但需要注意的另一点是,在
kwargs
的上下文中,
可选[…]
联合[…,无]
都是多余和不必要的。如果您立即将kwarg设置为
None
,则
mypy
和IDE都假定参数明显,并自动将参数视为
可选[…]

IDE:

mypy:


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

直到Python 3.9,如果您想提示一个可为null的值,您有两个选项:

导入键入
def foo(bar:typing.Optional[str]):
....
def foo(bar:typing.Union[str,None]):
....
在Python 3.9中,您不需要使用类型化模块:

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

@MartijnPieters难道我们不需要从键入和写入
可选[Dict]
可选[List]
而不是
可选[Dict]
导入
Dict
列表
。@Alireza是的,我在回答中已经说明了这一点。查找:旁注:您希望避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型。如果我错了,请更正我,但3.9允许使用
list
dict
作为类型提示(与
list
dict
)@user48956:我在3.9中添加了一节。关于
列表
目录
的旁注的重要性怎么强调都不过分。在查阅官方Python文档之后,直到这次讨论之前,我才意识到这是一个事实。为你们强调这一点干杯。有什么建议