Python 生成器表达式的 PEP 484 类型注释
Python's PEP 484 type annotation for Generator Expression
returns 和 generator expression 函数的正确类型注释是什么?
例如:
def foo():
return (x*x for x in range(10))
我不知道这是 -> Iterator[int]
、-> Iterable[int]
、-> Generator[int, None, None]
还是其他。
如果应该有一种——最好只有一种——显而易见的方法,那么显而易见的方法是什么在吗?
你提到的所有三种形式都列为valid alternatives in documentation,生成器表达式只是创建一个只产生的生成器。
引用 1:
A generator can be annotated by the generic type Generator[YieldType,
SendType, ReturnType]
.
引用 2:
If your generator will only yield values, set the SendType
and
ReturnType
to None
引用 3:
Alternatively, annotate your generator as having a return type of
either Iterable[YieldType]
or Iterator[YieldType]
:
快速说明:您的函数是“return是生成器的常规函数”,而不是“生成器函数”。要了解区别,请阅读 。
对于你的 foo
,我建议使用 -> Iterator[int]
。
说明
归结为你想要什么样的界面。
首先,让自己熟悉 python 文档中的 this page,其中定义了最重要的 Python 类型的层次结构。
你可以看到这些表达式 return True
:
import typing as t
issubclass(t.Iterator, t.Iterable)
issubclass(t.Generator, t.Iterator)
您还应该在同一页面上注意到 Generator
有 Iterator
没有的方法。这些方法是 send
、throw
和 close
(documentation), and they allow you to do more with generators than just simple single passthrough iteration. Check this question for examples of the possibilities with generators: python generator "send" function purpose?
回到选择界面。如果你想让别人像生成器一样使用你的生成器函数的结果,即
def gen(limit: int): -> Generator[int, None, None]
for x in range(limit):
yield x
g = gen(3)
next(g) # => 0
g.send(10) # => 1
那么你应该指定-> Generator[int, None, None]
.
但是请注意上面是废话。你实际上可以调用send
,但它不会改变执行,因为gen
不会对发送的值做任何事情(没有像 x = yield
这样的东西)。
知道了,就可以限制使用gen
的人的知识,定义为-> Iterator[int]
。通过这种方式,您可以与用户签订合同,“我的函数 return 是整数的迭代器,您应该这样使用它”。如果您稍后将实现更改为,例如
def gen(limit: int): -> Iterator[int]
return iter(list(range(limit)))
那些使用像 Generator
这样的 returned 对象的人(因为他们偷看了实现)会破坏他们的代码。但是,您不应该为此感到困扰,因为他们使用它的方式与合同中指定的方式不同。因此,这种损坏不是您的责任。
简单地说,如果您最终得到 Generator[Something, None, None]
(两个 None
),那么请考虑 Iterable[Something]
或 Iterator[Something]
。
Iterator
与 Iterable
的情况相同。如果您希望您的用户只能通过 iter
函数使用您的对象(因此可以在迭代上下文中使用,例如 [x for x in g]
),那么请使用 Iterable
。如果您希望他们在对象上同时使用 next
和 iter
,请使用 Iterator
.
备注
这种思路主要适用于 returned 值的注释类型。对于参数,您应该根据要在函数内的该对象上使用的接口(阅读:methods/functions)来指定类型。
returns 和 generator expression 函数的正确类型注释是什么?
例如:
def foo():
return (x*x for x in range(10))
我不知道这是 -> Iterator[int]
、-> Iterable[int]
、-> Generator[int, None, None]
还是其他。
如果应该有一种——最好只有一种——显而易见的方法,那么显而易见的方法是什么在吗?
你提到的所有三种形式都列为valid alternatives in documentation,生成器表达式只是创建一个只产生的生成器。
引用 1:
A generator can be annotated by the generic type
Generator[YieldType, SendType, ReturnType]
.
引用 2:
If your generator will only yield values, set the
SendType
andReturnType
toNone
引用 3:
Alternatively, annotate your generator as having a return type of either
Iterable[YieldType]
orIterator[YieldType]
:
快速说明:您的函数是“return是生成器的常规函数”,而不是“生成器函数”。要了解区别,请阅读
对于你的 foo
,我建议使用 -> Iterator[int]
。
说明
归结为你想要什么样的界面。
首先,让自己熟悉 python 文档中的 this page,其中定义了最重要的 Python 类型的层次结构。
你可以看到这些表达式 return True
:
import typing as t
issubclass(t.Iterator, t.Iterable)
issubclass(t.Generator, t.Iterator)
您还应该在同一页面上注意到 Generator
有 Iterator
没有的方法。这些方法是 send
、throw
和 close
(documentation), and they allow you to do more with generators than just simple single passthrough iteration. Check this question for examples of the possibilities with generators: python generator "send" function purpose?
回到选择界面。如果你想让别人像生成器一样使用你的生成器函数的结果,即
def gen(limit: int): -> Generator[int, None, None]
for x in range(limit):
yield x
g = gen(3)
next(g) # => 0
g.send(10) # => 1
那么你应该指定-> Generator[int, None, None]
.
但是请注意上面是废话。你实际上可以调用send
,但它不会改变执行,因为gen
不会对发送的值做任何事情(没有像 x = yield
这样的东西)。
知道了,就可以限制使用gen
的人的知识,定义为-> Iterator[int]
。通过这种方式,您可以与用户签订合同,“我的函数 return 是整数的迭代器,您应该这样使用它”。如果您稍后将实现更改为,例如
def gen(limit: int): -> Iterator[int]
return iter(list(range(limit)))
那些使用像 Generator
这样的 returned 对象的人(因为他们偷看了实现)会破坏他们的代码。但是,您不应该为此感到困扰,因为他们使用它的方式与合同中指定的方式不同。因此,这种损坏不是您的责任。
简单地说,如果您最终得到 Generator[Something, None, None]
(两个 None
),那么请考虑 Iterable[Something]
或 Iterator[Something]
。
Iterator
与 Iterable
的情况相同。如果您希望您的用户只能通过 iter
函数使用您的对象(因此可以在迭代上下文中使用,例如 [x for x in g]
),那么请使用 Iterable
。如果您希望他们在对象上同时使用 next
和 iter
,请使用 Iterator
.
备注
这种思路主要适用于 returned 值的注释类型。对于参数,您应该根据要在函数内的该对象上使用的接口(阅读:methods/functions)来指定类型。