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 Optionaltype hint. From PEP-484, I know I can use Optionalfor 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, orNoneis 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 dictand listcontainer types, but the default value for the akeyword argument shows that Noneis 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 Noneto 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 = Noneto set a default value, this documents the reason why Noneis 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[]= NoneNoneUnion[...]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 Nonevalue is not a 'subwidget id' after all, it's not part of the value, Noneis 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 dictand list, use typing.Dictand 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 Sequenceobjects, while dictis a Mappingtype:
旁注:然而,您想避免在类型提示中使用标准库容器类型,因为您无法说明它们必须包含哪些类型;因此,而不是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

