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
How should I use the Optional type hint?
提问by jacobcan118
I'm trying to understand how to use the Optional
type hint. From PEP-484, I know I can use Optional
for def test(a: int = None)
either as def test(a: Union[int, None])
or def test(a: Optional[int])
.
我试图了解如何使用Optional
类型提示。从PEP-484,我知道我可以使用Optional
的def 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, orNone
is 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 dict
and list
container types, but the default value for the a
keyword argument shows that None
is permitted too so use Optional[...]
:
因此,对于您的两个示例,您有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
Note that there is technically no difference between using Optional[]
on a Union[]
, or just adding None
to the Union[]
. So Optional[Union[str, int]]
and Union[str, int, None]
are exactly the same thing.
请注意,在技术上使用Optional[]
aUnion[]
或仅添加None
到Union[]
. 所以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 = None
to set a default value, this documents the reason why None
is 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[]
= None
None
Union[...]
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 None
value is not a 'subwidget id' after all, it's not part of the value, None
is 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 dict
and list
, use typing.Dict
and 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 Sequence
objects, while dict
is a Mapping
type:
旁注:然而,您想避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型;因此,而不是dict
和list
,使用typing.Dict
和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