Jon*_*han 128 python generator
Python生成器非常有用.它们优于返回列表的函数.但是,你可以len(list_returning_function()).有办法len(generator_function())吗?
更新:
当然len(list(generator_function()))会工作.....
我正在尝试使用我在我正在创建的新生成器中创建的生成器.作为新发电机计算的一部分,它需要知道旧发电机的长度.但是我想将它们与发生器保持相同的属性,特别是 - 不要将整个列表保存在内存中,因为它可能很长.
更新2:
假设发生器即使从第一步开始就知道它的目标长度.此外,没有理由维护len()语法.示例 - 如果Python中的函数是对象,我不能将长度分配给新生成器可以访问的此对象的变量吗?
Ros*_*ron 218
list如果你仍然想要在之后处理生成器元素,那么在其他答案中建议的转换是最好的方法,但是有一个缺陷:它使用O(n)内存.您可以在不使用那么多内存的情况下计算生成器中的元素:
sum(1 for x in generator)
Run Code Online (Sandbox Code Playgroud)
当然,要注意这可能比len(list(generator))普通的Python实现要慢,如果生成器足够长,内存复杂性很重要,那么操作需要相当长的时间.尽管如此,我个人更喜欢这个解决方案,因为它描述了我想要的东西,而且它没有给我任何额外的不需要的东西(例如所有元素的列表).
还要听听delnan的建议:如果你丢弃了生成器的输出,很可能有一种方法可以在不运行它的情况下计算元素的数量,或者以另一种方式计算它们.
Joc*_*zel 60
生成器没有长度,毕竟它们不是集合.
生成器是具有内部状态(和花哨语法)的函数.您可以重复调用它们以获取一系列值,因此您可以在循环中使用它们.但是它们不包含任何元素,因此要求生成器的长度就像要求函数的长度一样.
如果Python中的函数是对象,我不能将长度分配给新生成器可以访问的此对象的变量吗?
函数是对象,但您无法为它们分配新属性.原因可能是保持这样一个基本对象尽可能高效.
但是,您可以简单地(generator, length)从函数中返回对,或者将生成器包装在一个简单的对象中,如下所示:
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)
Run Code Online (Sandbox Code Playgroud)
unu*_*tbu 19
假设我们有一台发电机:
def gen():
for i in range(10):
yield i
Run Code Online (Sandbox Code Playgroud)
我们可以将生成器与已知长度一起包装在一个对象中:
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)
Run Code Online (Sandbox Code Playgroud)
实例LenGen是生成器本身,因为调用它们会返回迭代器.
现在我们可以使用lgen生成器来代替gen和访问len(lgen):
def new_gen():
for i in lgen():
yield float(i)/len(lgen)
for i in new_gen():
print(i)
Run Code Online (Sandbox Code Playgroud)
Gre*_*ill 13
你可以用len(list(generator_function()).但是,这会消耗生成器,但这是您可以找出生成多少元素的唯一方法.因此,如果您还想使用这些项目,您可能希望将列表保存在某处.
a = list(generator_function())
print(len(a))
print(a[0])
Run Code Online (Sandbox Code Playgroud)
您可以使用reduce.
对于 Python 3:
>>> import functools
>>> def gen():
... yield 1
... yield 2
... yield 3
...
>>> functools.reduce(lambda x,y: x + 1, gen(), 0)
Run Code Online (Sandbox Code Playgroud)
在 Python 2 中,reduce位于全局命名空间中,因此不需要导入。
你可以send用作黑客:
def counter():
length = 10
i = 0
while i < length:
val = (yield i)
if val == 'length':
yield length
i += 1
it = counter()
print(it.next())
#0
print(it.next())
#1
print(it.send('length'))
#10
print(it.next())
#2
print(it.next())
#3
Run Code Online (Sandbox Code Playgroud)
您可以len()通过创建自己的可迭代对象,将生成器的优点与 的确定性结合起来:
class MyIterable(object):
def __init__(self, n):
self.n = n
def __len__(self):
return self.n
def __iter__(self):
self._gen = self._generator()
return self
def _generator(self):
# Put your generator code here
i = 0
while i < self.n:
yield i
i += 1
def next(self):
return next(self._gen)
mi = MyIterable(100)
print len(mi)
for i in mi:
print i,
Run Code Online (Sandbox Code Playgroud)
这基本上是 的一个简单实现xrange,它返回一个可以获取 len 的对象,但不创建显式列表。
| 归档时间: |
|
| 查看次数: |
94561 次 |
| 最近记录: |