python - 我应该如何使用 Optional 类型提示?
问题描述
我试图了解如何使用Optional
类型提示。从PEP-484,我知道我可以Optional
使用def test(a: int = None)
asdef 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]
,我为什么要使用Optional[]
?
解决方案
Optional[...]
是 的简写符号Union[..., None]
,告诉类型检查器需要或 None
需要特定类型的对象。...
代表任何有效的类型提示,包括复杂的复合类型或Union[]
更多类型。每当您有一个具有默认值的关键字参数时None
,您都应该使用Optional
. (注意:如果您的目标是 Python 3.10 或更新版本,PEP 604引入了更好的语法,见下文)。
因此,对于您的两个示例,您有dict
和list
容器类型,但关键字参数的默认值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[]
在 a 上使用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
毕竟,该值不是“子小部件 id”,它不是值的一部分,None
旨在标记缺少值。
旁注:除非您的代码只需要支持 Python 3.9 或更高版本,否则您要避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型。因此,代替dict
and ,分别list
使用typing.Dict
and typing.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
在 Python 3.9 及更高版本中,标准容器类型已全部更新以支持在类型提示中使用它们,请参阅PEP 585。但是,虽然您现在可以使用dict[str, int]
or list[Union[int, str]]
,但您仍然可能希望使用更具表现力Mapping
和Sequence
注释来指示函数不会改变内容(它们被视为“只读”),并且函数可以使用分别用作映射或序列的任何对象。
Python 3.10 将|
联合运算符引入类型提示,请参阅PEP 604。而不是Union[str, int]
你可以写str | int
. 与其他类型提示语言一致,在 Python 3.10 及更高版本中表示可选参数的首选(且更简洁)方式现在是Type | None
,例如str | None
or list | None
。
推荐阅读
- sql - Oracle listagg - 我可以根据 listagg 选择的值从其他表中提取数据吗
- git - 支持除 GitHub 之外的其他 git 存储库
- tensorflow - 让 Tensorboard Profiler 在 Windows 中运行
- excel - 将范围设置为最后一行和打印区域结束之间的空白空间 - Excel VBA PrintArea
- java - 在 Java 中使用泛型接口作为方法参数
- c# - 使用 Apache Docker 在 Linux 中托管 ASP.NET Core
- c - 释放链表内存时的 valgrind 错误
- python - 来自子解析器的顶级解析器上的 Python argparse set_defaults
- c# - 在 macOS 上读取引导扇区 CD 驱动器
- vue.js - Vue 渲染一个组件两次