我试着理解如何使用Optional
类型提示,从PEP-484中,我知道我可以将Optional
用作def 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[]
呢?
6条答案
按热度按时间twh00eeo1#
Optional[...]
是Union[..., None]
的简写符号,告诉类型检查器需要特定类型的对象,* 或者需要 *None
。...
代表 * 任何有效的类型提示 *,包括复杂的复合类型或更多类型的Union[]
。每当您有一个具有默认值None
的关键字参数时,您应该使用Optional
。(注意:如果你的目标是Python 3.10或更新版本,PEP 604引入了更好的语法,见下文)。对于您的两个示例,您有
dict
和list
容器类型,但是a
关键字参数的默认值显示None
也是允许的,因此使用Optional[...]
:在
Union[]
上使用Optional[]
,或者只是在Union[]
上添加None
,从技术上讲没有区别,所以Optional[Union[str, int]]
和Union[str, int, None]
是完全一样的。就我个人而言,当为一个使用
= None
来设置默认值的关键字参数设置类型时,我会坚持 always usingOptional[]
,这说明了为什么None
可以更好地被允许。此外,它可以更容易地将Union[...]
部分移到一个单独的类型别名中,或者在以后某个参数成为强制性的时移除Optional[...]
部分。例如,假设您有
型
则通过将
Union[str, int]
拉出到类型别名中来改进文档:将
Union[]
移到别名中的重构变得更加容易,因为使用了Optional[...]
而不是Union[str, int, None]
。毕竟,None
值不是一个“subwidget id”,它不是值的一部分,None
旨在标记值的缺失。旁注:除非你的代码只需要支持Python 3.9或更新版本,否则你会希望避免在类型提示中使用标准库容器类型,因为你不能说明它们必须包含什么类型。因此,不要使用
dict
和list
,而要分别使用typing.Dict
和typing.List
。并且,当只从容器类型中 * 阅读 * 时,你也可以接受任何不可变的抽象容器类型;列表和元组是Sequence
对象,而dict
是Mapping
类型:在Python 3.9及更高版本中,标准容器类型已经全部更新,以支持在类型提示中使用它们,参见PEP 585。* 但是 *,尽管你现在 * 可以 * 使用
dict[str, int]
或list[Union[int, str]]
,您可能仍然希望使用更具表达力的Mapping
和Sequence
注解来指示函数不会改变内容(它们被视为“只读”),并且这些函数将分别与作为Map或序列工作的 any 对象一起工作。Python 3.10引入了
|
并集运算符到类型提示中,参见PEP 604。你可以写str | int
来代替Union[str, int]
。与其他类型提示语言一致,在Python 3.10及以上版本中表示可选参数的首选(也更简洁)方式现在是Type | None
,例如str | None
或list | None
。3gtaxfhh2#
直接从mypy打字模块文档。
Optional[str]
只是Union[str, None]
的缩写或别名,它的存在主要是为了帮助函数签名看起来更干净一些。针对Python 3.10+的更新
现在也可以使用管道操作符。
ktecyv1j3#
虽然接受的答案是正确的答案,但需要注意的是,* 在
kwargs
的上下文中 *,Optional[...]
和Union[..., None]
都是多余的和不必要的。如果您立即将kwarg设置为None
,则mypy
和IDE都假定这是显而易见的,并 * 自动 * 将arg视为Optional[...]
。IDE:
作者:
对于变量和方法/函数的返回值,
Optional[...]
仍然是必需的,但是,在这些情况下,mypy
不知道自动假设什么。daupos2t4#
注意,从Python 3.10开始,你可以简化你的代码,输入如下:
eimct9ow5#
在Python 3.9之前,如果你想提示一个nullable值,你有两个选择:
从Python 3.9开始,你不需要使用类型模块:
k10s72fa6#
正如在几个注解中提到的,从Python 3.7开始,就可以通过
__future__
导入来使用新样式的类型注解:至于自动回答这个问题和许多其他通用的最佳实践问题,我强烈推荐使用pyupgrade来自动重新格式化类型注解和代码的其余部分,使其具有现代Python风格。对于单个文件,在添加
__future__
导入后,运行pyupgrade --py37-plus --keep-runtime-typing file.py
。如果你使用Git,那么
pyupgrade
可以被设置为一个预提交钩子,这样你的代码就可以一直保持现代化用途:注意:如果使用Pydantic、FastAPI或其他依赖于运行时类型的类似工具,则需要
--keep-runtime-typing
参数。否则,可以安全地省略此参数。