无限生成器有表达式吗?


119

是否有一个可以生成无限元素的简单生成器表达式?

这是一个纯粹的理论问题。此处无需“实用”答案:)


例如,很容易制作一个有限生成器:

my_gen = (0 for i in xrange(42))

但是,要制作一个无限个,我需要用虚假函数“污染”我的名称空间:

def _my_gen():
    while True:
        yield 0
my_gen = _my_gen()

在单独的文件中处理,import以后-ing不计算在内。


我也知道这itertools.repeat完全可以做到。我很好奇是否有没有这种情况的一线解决方案。


9
实际上,您实际上不需要污染名称空间……只需命名函数my_gen,然后执行即可my_gen = my_gen()
6502

2
del _my_gen如果您不想混淆两者,也可以使用
John La Rooy

Answers:


133
for x in iter(int, 1): pass
  • 两参数iter=零参数可调用+哨兵值
  • int() 总是回来 0

因此,iter(int, 1)是一个无限的迭代器。显然,此特定主题有很多变体(尤其是一旦添加lambda到组合中)。特别注意的一个变体是iter(f, object()),因为使用新创建的对象作为哨兵值几乎可以保证无限迭代器,而与用作第一个参数的可调用对象无关。


3
一种非常有趣的方法,iterint我们常常忘记的属性一起使用。
Senthil Kumaran

3
您可以使用此魔术食谱进行模拟itertools.countcount = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1)))
Coffee_Table

1
只是为了解释这里发生的事情:当iter-function用两个参数调用时,它的行为与正常情况略有不同: iter(callable, sentinel) -> iteratorcallable迭代器的每次迭代都会调用参数1,直到返回值为止sentinel。然而,由于int()总是会返回0,我们可以称之为int()永远不会达到1。这实际上将产生无限名单0
Olsgaard

217

itertools 提供了三个无限生成器:

我不知道标准库中的任何其他内容。


由于您要求单线运输:

__import__("itertools").count()

18
回复:repeat(x,times =∞)- 谁都不知道,没有符号-忽略该参数将永远重复运行
Mr_and_Mrs_D 2016年

提出了这样的建议,因为(尽管ncoghlan的回答直接解决了OP的问题),但这种做法更为普遍。
休·沃尔特斯

这比iter(int, 1)咒语更具可读性。太糟糕了itertools,没有一种endlessly()方法的唯一目的就是这样做。itertools.count()也不是那么可读。
BallpointBen

19

您可以遍历可调用的可返回的常量,该常量始终与iter()的哨兵不同

g1=iter(lambda:0, 1)

8
我既喜欢又讨厌这个……我喜欢它能以很少的角色实现我想要的功能,但是却讨厌没人会看着它,也不知道它应该做什么。
ArtOfWarfare

1
知道iter(这里有额外的哨兵)的语法和lambda(这里没有任何传递的参数,只是return 0)的语法,唯一令人讨厌的地方是那个谜g1
斯瓦沃米尔Lenart

@SławomirLenart男人从来没有得到它。只是小巧的所以我喷了1克。
user237419

8

您的操作系统可能提供可用作无限生成器的功能。例如在Linux上

for i in (0 for x in open('/dev/urandom')):
    print i

显然,这没有效率

for i in __import__('itertools').repeat(0)
    print i

11
/ dev / urandom解决方案取决于\ns时不时出现的……太棒了!:)
hugomg 2011年

5

没有一个在内部不使用另一个定义为类/函数/生成器的无限迭代器(不是-expression,带有的函数yield)。生成器表达式始终从可迭代的迭代器中提取,除了过滤和映射其项外什么也不做。您不能只从有限的项目到无限的项目map和或者filter您需要while(或者一个for不会终止的项,这正是我们仅使用for有限迭代器所不能拥有的)。

琐事:PEP 3142在表面上是相似的,但是仔细检查似乎仍然需要该for子句(因此(0 while True)对您而言没有),即仅提供的快捷方式itertools.takewhile


正如我所怀疑的那样……那么我们可以确定没有一个容易使用的无限生成器吗?(可悲的是,xrange(0,1,-1)无效...)
hugomg

2
@missingno:from itertools import repeat, count, cycle对大多数人来说,它可能算作“随时可用”。
ncoghlan 2011年

1
糟糕,我忘了2个论点iter。无限迭代器实际上可以作为内置函数使用-参见我的回答:)
ncoghlan 2011年

5

相当丑陋和疯狂(但是非常有趣),但是您可以通过使用一些技巧从表达式构建自己的迭代器(无需根据需要“污染”您的命名空间):

{ print("Hello world") for _ in
    (lambda o: setattr(o, '__iter__', lambda x:x)
            or setattr(o, '__next__', lambda x:True)
            or o)
    (type("EvilIterator", (object,), {}))() } 

您显然喜欢LISP
Faissaloo

1
:@Faissaloo事实上......你可能会发现一个旧的网页我写了一个更疯狂的表达baruchel.github.io/python/2018/06/20/...
托马斯巴吕谢尔

2

例如,也许您可​​以使用这样的装饰器:

def generator(first):
    def wrap(func):
        def seq():
            x = first
            while True:
                yield x
                x = func(x)
        return seq
    return wrap

用法(1):

@generator(0)
def blah(x):
    return x + 1

for i in blah():
    print i

用法(2)

for i in generator(0)(lambda x: x + 1)():
    print i

我认为可以进一步改善摆脱这些丑陋的状况()。但是,这取决于您希望创建的序列的复杂性。一般来说,如果可以使用函数来表达序列,那么生成器的所有复杂性和语法糖都可以隐藏在装饰器或类似装饰器的函数内部。


9
OP要求一个单线纸,而您要提供一个带有三层嵌套def和封闭式的10行装饰器?;)

2
@delnan好吧,但是如果您一次定义装饰器,就可以拥有一个衬板,不是吗?据我了解,目的是使每个附加的无限生成器都在一行中实现。这就是这里介绍的内容。你可以拥有(2^x),你可以拥有(x)。如果您有所改善,可能还包括斐波那契等
。– jux

没有回答我的问题,但是您怎么能不喜欢所有那些蓬松的纽扣呢?顺便说一句,我非常确定您可以摆脱seqwrap
掉多余的部分,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.