如何计算generator()的长度
Python中的生成器非常有用。它们比返回列表的函数有一些优势。不过,你可以用 len(list_returning_function())
来获取列表的长度。那么,有没有办法用 len(generator_function())
来获取生成器的长度呢?
更新:
当然,len(list(generator_function()))
是可以工作的.....
我正在尝试在我创建的新生成器中使用我已经创建的一个生成器。在新生成器的计算过程中,它需要知道旧生成器的长度。不过,我希望这两个生成器能保持在一起,并且都具备生成器的特性,特别是——不把整个列表都放在内存中,因为它可能会非常长。
更新 2:
假设这个生成器从一开始就“知道”它的目标长度。而且,没有必要保持 len()
这种语法。举个例子——如果Python中的函数是对象,我能不能把长度赋值给这个对象的一个变量,这样新生成器就能访问到呢?
8 个回答
假设我们有一个生成器:
def gen():
for i in range(10):
yield i
我们可以把这个生成器和它的已知长度放在一个对象里:
import itertools
class LenGen(object):
def __init__(self,gen,length):
self.gen=gen
self.length=length
def __call__(self):
return itertools.islice(self.gen(),self.length)
def __len__(self):
return self.length
lgen=LenGen(gen,10)
LenGen
的实例本身就是生成器,因为调用它会返回一个迭代器。
现在我们可以用lgen
生成器来替代gen
,并且也可以访问len(lgen)
:
def new_gen():
for i in lgen():
yield float(i)/len(lgen)
for i in new_gen():
print(i)
在其他回答中提到的把内容转换成 list
的方法,如果你还想在之后处理生成器的元素,那确实是个不错的选择,但有一个缺点:它会使用 O(n) 的内存。你可以用下面的方法来计算生成器中的元素数量,而不需要那么多内存:
sum(1 for x in generator)
当然,要注意的是,这种方法在常见的 Python 实现中可能会比 len(list(generator))
慢。如果生成器的长度足够大,内存的使用情况会影响速度,这个操作可能会花费不少时间。不过,我个人更喜欢这个方法,因为它清楚地表达了我想要的结果,而且不会给我额外的东西,比如所有元素的列表。
另外,听听 delnan 的建议:如果你不需要生成器的输出,很可能有其他方法可以在不运行生成器的情况下计算元素的数量,或者用其他方式来计数。
生成器没有长度,毕竟它们不是集合。
生成器是具有内部状态的函数(还有一些特殊的语法)。你可以多次调用它们来获取一系列的值,所以可以在循环中使用它们。但它们并不包含任何元素,所以问生成器的长度就像问一个函数的长度一样。
如果Python中的函数是对象,那我能不能把这个对象的长度赋值给一个变量,让新生成器可以访问呢?
函数确实是对象,但你不能给它们添加新的属性。这样做的原因可能是为了让这种基本对象尽可能高效。
不过,你可以简单地从你的函数返回(生成器, 长度)
的组合,或者像这样把生成器包装在一个简单的对象里:
class GeneratorLen(object):
def __init__(self, gen, length):
self.gen = gen
self.length = length
def __len__(self):
return self.length
def __iter__(self):
return self.gen
g = some_generator()
h = GeneratorLen(g, 1)
print len(h), list(h)