函数类型提示:返回特定值集合的函数

55
我有一个函数,它只能返回类型为 T 的 abc。由于这些值在函数的上下文中具有特殊意义,因此我希望在函数签名中包含这个信息。如何做到这一点?
目前,我使用以下代码:
def fun(...) -> "a or b or c":
    #briefly explain the meaning of a, b and c in its docstring

这是正确的吗?

我知道我可以做到这个。

def fun(...) -> T:
    # briefly explain the meaning of a, b and c in its docstring

但是正如我所说,我希望在签名中表达这个函数仅返回那些特定的值。


为什么不创建一个特定值的枚举,然后指定返回类型为该枚举呢? - Noctis Skytower
3个回答

91

你可以使用字面类型来完成这个操作。

from typing_extensions import Literal
# from typing import Literal  # Python 3.8 or higher

def fun(b: int) -> Literal["a", "b", "c"]:
    if b == 0:
        return "a"
    if b == 1:
        return "b"
    return "d"

mypy 能检测到 return "d" 语句是无效的:

error: Incompatible return value type (got "Literal['d']",
expected "Union[Literal['a'], Literal['b'], Literal['c']]")

Python 3.8

由于PEP 586的支持,Literal在Python 3.8的typing模块中已默认包含。点击此处查看详情。


虽然在许多情况下这是一个完全有效的解决方案,但我想指出对于热心读者来说,Blckknght的答案(https://dev59.com/X1kS5IYBdhLWcg3w1JlK#39398431)在许多情况下是更好的方法,因为它将文字值委托给枚举,从而避免了重复(在签名和实现之间),保持更灵活(您可以添加值而不更改签名),并使函数更易于使用(例如,您可以与枚举进行比较)。 - bgusach

18

仅使用类型提示无法指定您的函数仅返回类型值的子集。如名称所示,类型提示只与类型有关,而不是值。

但是,您可以创建一个新的enum.Enum子类型,其中仅包含要返回的值,并在该函数中使用它。然后,您可以使用类型提示指定返回枚举类型。

import enum

class cmp_results(enum.IntEnum):
    less = -1
    equal = 0
    greater = 1

def my_cmp_function(x, y) -> cmp_results:
    if x < y: return cmp_results.less
    elif x == y: return cmp_results.equal
    else: return cmp_results.greater

这可能有些过头了。只是将返回类型提示为int(并记录具体的值)可能已经足够了。


12
我不认为这是过度了。相反,这是静态类型检查的好处之一:您可以精确地指定函数可能返回什么。 lessequalgreater仅是少量int值的别名是实现细节。(而且如果您不想利用int类型已经支持的负/零/正划分,选择的特定值也无关紧要。) - chepner
这个枚举的想法看起来很有趣,而且它还有一个额外的好处,就是当调用帮助时,我可以通过它来操纵输出,以获得漂亮的文档。 - Copperfield
3
@Copperfield,你可能考虑接受Cesar提供的Literal types答案,这似乎是一种新的、更好的选择。 - Ivo Merchiers
@IvoMerchiers 我认为这比将值硬编码到“Literal”提示中要好。 - bgusach

0
如果所有的类型都完全相同,只需将其添加为返回类型:
def func(...) -> T: # or int or whatever else

我想在函数签名中表达该函数仅返回特定值。
类型提示不指定名称或值,它们只指定一个类型;类型检查器试图对提供的类型进行操作。
如果您只是为了文档目的而这样做,可以添加 'a or b or c';用户会理解,但类型检查器不会,并且它们绝对不会对其进行操作。

它们全部都是类型为 T 的。 - Moses Koledoye
所有这些都是同一类型的,例如该函数只返回 1-10 - Copperfield
2
@Jim -- 很遗憾,使用PEP 484类型注释无法实现这一点。在Python的渐进式类型系统(以及大多数类型系统)中,您只能添加注释,说明您将返回特定类型的值 - 不可能限制类型的输出值。确实有一些类型系统可以让您做到这一点(例如依赖类型),但是PEP 484目前不支持依赖类型。 - Michael0x2a
2
@Michael0x2a 可能你当时是这样想的,我的评论是在我误解问题并提出了一个“Union”解决方案时发表的。我们现在意见一致。 - Dimitris Fasarakis Hilliard
1
啊,这很有道理——我没有看到你帖子的原始版本。在这种情况下,你是对的,我们在这里达成了一致意见——抱歉误解了 :) - Michael0x2a
显示剩余3条评论

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