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文档之后,直到这次讨论之前,我才意识到这是一个事实。为你们强调这一点干杯。有什么建议