"void"函数中的NoReturn vs. None - Python 3.6中的类型注释

55

Python 3.6支持类型注释,例如:

def foo() -> int:
    return 42

如果一个函数没有返回任何内容,应该使用什么?PEP484 的示例通常将 None 用作返回类型,但也可以使用 typing 包中的 NoReturn 类型。

因此,问题是什么是首选使用的,以及什么被认为是最佳实践:

def foo() -> None:
    #do smth
或者
from typing import NoReturn

def foo() -> NoReturn:
    #do smth

4
None 的类型不是 None,而是 NoneType - Willem Van Onsem
8
根据 PEP484,None 在类型提示中被视为等同于 type(None),即 NoneType - ByAgenT
1个回答

71

NoReturn 意味着这个函数 永远不会返回一个值

这个函数要么不会终止,要么总是抛出异常"typing模块提供了一种特殊类型NoReturn来注释那些从不正常返回的函数。例如,一个无条件抛出异常的函数..".

from typing import NoReturn

def stop() -> NoReturn:
    raise RuntimeError('no way')

也就是说,x = foo_None() 是类型有效但可疑,而 x = foo_NoReturn() 是无效的。

除了从来没有可分配的结果之外, NoReturn 在分支分析中还有其他影响:foo_NoReturn();unreachable...。有关详细讨论,请参见“需要一个 NoReturn 类型 #165”

为了进行分支分析,必须知道哪些调用永远不会正常返回。例如,sys.exit(始终通过异常返回)和 os.exit(永远不会返回)。


5
有趣的是,对于可能会抛出异常的函数而言,Optional[NoReturn]却不能通过mypy的检查("error: Missing return statement"),尽管该函数要么不返回任何内容,要么返回None...也许与NoReturn同时也是底层类型有关。 - joel
1
@joel:因为至少在概念上,“NoReturn”并不是一种类型,它是一种表示“缺乏类型”的指示,因为它没有关联的值,甚至没有“None”。它甚至不能被赋值,所以你可能不能(至少肯定不应该)在“Union”、“TypeAlias”等中使用它。 - MestreLion
1
@MestreLion 我不明白;一个类型并不需要有值才能成为一个类型。Idris中的Void和Scala中的Nothing就是例子。我看不出任何类型理论上的理由,你不能在Union中使用它。虽然在Python中它并不是很有用,但我认为这是有效的。 - joel
1
@joel 确实,从概念上讲,类型不需要值。但是在 f(...) -> type: 注释的上下文中,我们指的是返回值的类型。它有一个非常具体的含义,而不是函数退出的一般注释,包括“如何”,“何时”或“是否”。允许这样做需要改变 -> 的语义,正如 PEP 所描述的那样。 - MestreLion
2
@OliverAngelil 在返回None的函数中使用-> None。这当然是显而易见的。但当我开始为自己的代码添加类型注释时,我忽略了一个问题:没有明确return语句的函数将具有隐式的return None。因此,你的示例函数应该是def foo() -> None。如果你有一个没有参数的return语句,那么return的参数会被隐式地设置为None - pyansharp
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接