【问题标题】:Is there an expression for an infinite iterator?是否有无限迭代器的表达式?
【发布时间】:2011-08-09 21:08:27
【问题描述】:

是否有可以产生无限迭代器的直接表达式?

这是一个纯粹的理论问题。这里不需要“实用”的答案:)


例如,很容易使用生成器表达式来制作有限迭代器:

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

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

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

在一个单独的文件中做事,之后import-ing 不算。


我也知道itertools.repeat 正是这样做的。我很好奇是否有没有它的单线解决方案。

【问题讨论】:

  • 你实际上不需要污染你的命名空间......只需将函数命名为my_gen,然后执行my_gen = my_gen()
  • 如果不想混淆两者,也可以使用del _my_gen

标签: python iterator generator infinite-loop


【解决方案1】:

itertools 提供三个无限迭代器:

我不知道标准库中还有其他人。


既然您要求单线:

__import__("itertools").count()

【讨论】:

  • Re: repeat(x, times=∞) - 没有 符号供任何想知道的人使用 - 省略参数会使重复运行永远
  • 赞成,因为(虽然 ncoghlan 的回答直接解决了 OP 的问题)这更普遍适用。
  • 这比iter(int, 1) 咒语更易读。太糟糕了 itertools 没有 endlessly() 方法,其唯一目的就是这样做; itertools.count() 也不是那么可读。
【解决方案2】:

你可以迭代一个可调用的,返回一个总是不同于 iter() 的哨兵的常量

g1=iter(lambda:0, 1)

【讨论】:

  • 我既喜欢又讨厌这个......我喜欢它用这么少的角色完成了我想要的事情,但讨厌没有人会看到它并知道它应该做什么。
  • 知道iter的语法(这里有额外的标记)和lambda的语法(这里没有任何传递的参数,只是return 0),唯一讨厌的地方就是那个神秘的@ 987654325@.
  • @SławomirLenart 男人永远不会明白。只是它太小了,所以我喷了 1g。
【解决方案3】:

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

{ 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,), {}))() } 

【讨论】:

【解决方案4】:
for x in iter(int, 1): pass
  • 双参数 iter = 零参数可调用 + 标记值
  • int() 总是返回 0

因此,iter(int, 1) 是一个无限迭代器。显然,这个特定主题有大量的变化(尤其是在您将lambda 添加到组合中后)。特别注意的一个变体是iter(f, object()),因为使用新创建的对象作为标记值几乎可以保证无限迭代器,而不管第一个参数使用的可调用对象如何。

【讨论】:

  • 非常有趣的方式来使用 iterint 的属性,我们很多时候都忘记了。
  • 你可以使用这个神奇的配方来模拟itertools.count:count = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1)))
  • 只是为了解释这里发生了什么:当使用两个参数调用iter-函数时,它的行为与正常情况略有不同:iter(callable, sentinel) -> iterator。参数 1,callable 为迭代器的每次迭代调用,直到它返回 sentinel 的值。然而,由于int() 将始终返回0,我们可以永远调用int() 而永远不会达到1。这实际上将产生0 的无限列表
【解决方案5】:

您的操作系统可能会提供可以用作无限生成器的东西。例如在linux上

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

显然这不如

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

【讨论】:

  • /dev/urandom 解决方案取决于不时出现的\ns……狡猾! :)
【解决方案6】:

也许你可以使用像这样的装饰器:

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

用法(一):

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

for i in blah():
    print i

用法(二)

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

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

【讨论】:

  • OP 要求使用 oneliner,而您提供了一个 10 行装饰器,带有三重嵌套 def 和闭包? ;)
  • @delnan 好吧,但是如果你定义了一次装饰器,你就可以拥有一个衬垫,不是吗?据我了解,目的是在一行中实现每个额外的无限生成器。这就是这里介绍的内容。你可以有(2^x),你可以有(x)。如果你改进一点,可能还有斐波那契等。
  • 没有回答我的问题,但是你怎么能不喜欢所有那些蓬松的封闭物呢?顺便说一句,我很确定您可以通过摆脱 seq 并将代码直接缩进到 wrap 来摆脱额外的括号
【解决方案7】:

None 内部不使用另一个定义为类/函数/生成器的无限迭代器(不是 - 表达式,一个带有 yield 的函数)。生成器表达式总是从另一个可迭代对象中提取,并且除了过滤和映射其项目之外什么都不做。您不能仅使用mapfilter 从有限项变为无限项,您需要while(或不会终止的for,这正是我们不能仅使用@ 987654327@ 和有限迭代器)。

琐事:PEP 3142 表面上相似,但仔细检查后似乎仍然需要for 子句(所以你没有(0 while True)),即只提供itertools.takewhile 的快捷方式。

【讨论】:

  • 正如我所怀疑的......我们可以确定没有现成的无限生成器可以滥用吗? (遗憾的是,xrange(0,1,-1) 不起作用...)
  • @missingno: from itertools import repeat, count, cycle 对大多数人来说可能算作“随时可用”。
  • 糟糕,我忘记了 2-argument iter。无限迭代器实际上可以作为内置函数使用 - 请参阅我的答案:)
猜你喜欢
  • 2011-03-09
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
相关资源
最近更新 更多