我刚刚发现各种itertools函数返回的类类型不被Python类型系统视为生成器。
首先,让我们来看一下设置:
我找到了这个替代方案:
我希望这样做的一个例子是,如果序列的评估可能会引发异常,并且我希望该异常从
我不喜欢
我愿意忽略“不寻常”的迭代器,这意味着如果有人实现了一个自定义迭代器,但不符合生成器的条件,我可以忽略它,但我不愿意对itertools采用错误的行为,因为它们相当受欢迎。
首先,让我们来看一下设置:
import collections
import glob
import itertools
import types
ig = glob.iglob('*')
iz = itertools.izip([1,2], [3,4])
然后:
>>> isinstance(ig, types.GeneratorType)
True
>>> isinstance(iz, types.GeneratorType)
False
glob.iglob()
的结果,或者任何典型的生成器,都是types.GeneratorType
类型。但是itertools的结果不是这样的。如果我想编写一个必须急切地评估输入序列的函数,这会导致很多混乱 - 我需要知道它是否是生成器。我找到了这个替代方案:
>>> isinstance(ig, collections.Iterator)
True
>>> isinstance(iz, collections.Iterator)
True
但这并不是最理想的,因为无论 x
是一个具体(立即计算)的序列还是一个生成器(延迟计算),iter(x)
都是一个 Iterator
。
最终目标是像这样:
def foo(self, sequence):
"""Store the sequence, making sure it is fully
evaluated before this function returns."""
if isinstance(sequence, types.GeneratorType):
self.sequence = list(sequence)
else:
self.sequence = sequence
我希望这样做的一个例子是,如果序列的评估可能会引发异常,并且我希望该异常从
foo()
而不是从后续使用self.sequence
中引发。我不喜欢
types.GeneratorType
的方法,因为它会产生一些误报--我不想不必要地构造输入列表的副本,因为它可能很大。我愿意忽略“不寻常”的迭代器,这意味着如果有人实现了一个自定义迭代器,但不符合生成器的条件,我可以忽略它,但我不愿意对itertools采用错误的行为,因为它们相当受欢迎。
GeneratorType
是“通过调用生成器函数产生的生成器迭代器对象的类型”。iglob
是通过调用带有yield
的Python函数_iglob
来实现的,但izip
是用C实现的。 - jonrsharpeizip_type
的tp_base
为 null。我想知道为什么会这样——tp_base
在 Python 2.2 中被添加,而 itertools 是在 2.3 中添加的,所以它们可以使用它,但却没有使用。我不确定是因为时间不对劲,还是因为 itertools 类型不想子类化GeneratorType
,或者有一些具体的原因。 - John Zwinckisinstance(sequence, (types.GeneratorType, collections.Iterator))
进行检查。 - Netwave