如何在Python 3中为生成器添加注释?

61
Python 3.x 支持(可选)函数注解:
def add_ints(x:int, y:int) -> int :
    return x+y

有时候我会遇到如何表示给定的“类型”可以被表示的问题,而这一次,我有一个返回生成器的函数:
def myfunc(x: [int]) -> "generator that returns ints":
    #                     ^~~~~~~~~~~~~~~~~~~~~~~~~~
    return (n for n in x if n%2 == 0)

我应该如何注释返回值?有没有可以参考的文献?

具体而言,您试图通过添加此注释来实现什么目的?Python似乎仅需要它是一个有效表达式,并且不在内部使用它。似乎没有指导方针或标准,因此我建议根据您的情况选择最简单的方法即可。 - KSab
@KSab 感谢您的评论。了解缺乏指南对我来说是一个好的开始...虽然Python在内部不使用注释,但无效表达式会被捕获,因此我不能只是 -> generator(int) 而不将其变成字符串。 - Yosh
我想你可以使用types.GeneratorType(请参见https://docs.python.org/2/library/types.html),但是你不能指定它是一个“int”的生成器(Python的生成器可以返回多种类型)。如果你只是为了自己的类型检查而这样做,我认为没有理由不使用字符串标识符或全局变量。 - KSab
1
看起来types.GeneratorType正是我要找的(我为什么没搜这个呢!)。谢谢你建议我也可以使用字符串或变量,只是我不确定是否可以接受。你能再花点时间把它发成答案吗,这样我就可以接受了吗? - Yosh
2个回答

81

虽然存在 Generator[x, y, z],但大多数情况下,您可能希望使用更简洁的 Iterator

def fn(x: int) -> Iterator[int]:
    return (n for n in range(x) if n%2 == 0)

同样适用于yield

def fn(x: int) -> Iterator[int]:
    for n in range(x):
        yield n

1
这是一个非常好的答案,取决于最小值。 - Joseph King
1
正解,99%的时间,“生成器”是一种实现细节,而公共返回类型是“迭代器”。实际上,很少有你想让调用者知道你使用了生成器来实现该功能。 - Silvio Mayolo
2
你甚至可以更抽象地声明返回类型为“Iterable”,因为所有迭代器都应该有一个“__iter__”方法(返回自身)。 - Blckknght
2
@Blckknght。我认为Iterator更好,因为它更具体。使用Iterable,调用next(fn(1))将无法通过类型检查:Iterable没有__next__方法。 - Conchylicultor

54

typing 模块定义了 Generator 类型,您可以像这样使用:

Generator[yield_type, send_type, return_type] 

另见PEP 0484


生成器既没有发送类型(send type)也没有返回类型(return type)的情况怎么办?PEP规范对此并不明确。 - z33k
11
如果你的生成器只会产生值,将SendType和ReturnType都设置为None。- 来自Generator文档。 - zvone
4
使用迭代器更简单,可以参考Conchylicultor的回答。 - k107
1
看起来你应该只需要使用Generator[yield_type],如果其他的可以是None的话。 - user48956
1
自从Python 3.9版本开始,typing.Generator已被弃用。现在应该使用collections.abc.Generator - Daniel Walker

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