Есть ли выражение для бесконечного генератора? - PullRequest
98 голосов
/ 21 апреля 2011

Есть ли прямое выражение генератора, которое может дать бесконечные элементы?

Это чисто теоретический вопрос.Здесь нет необходимости в «практическом» ответе:)


Например, легко сделать конечный генератор:

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

Однако, чтобы сделать бесконечный мне нужен«загрязнить» мое пространство имен фиктивной функцией:

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

Делать вещи в отдельном файле и import - позже не считается.


Я также знаючто itertools.repeat делает именно это.Мне любопытно, есть ли однострочное решение без этого.

Ответы [ 7 ]

171 голосов
/ 21 апреля 2011

itertools предоставляет три бесконечных генератора:

Не знаюне знаю ни о каких других в стандартной библиотеке.


Поскольку вы запросили однострочник:

__import__("itertools").count()
112 голосов
/ 21 апреля 2011
for x in iter(int, 1): pass
  • Два аргумента iter = вызываемый без аргумента + часовой параметр
  • int() всегда возвращает 0

Следовательно, iter(int, 1) - бесконечный итератор. Очевидно, существует огромное количество вариаций на эту конкретную тему (особенно после добавления lambda в микс). Один вариант особого примечания - iter(f, object()), поскольку использование только что созданного объекта в качестве значения часового практически гарантирует бесконечный итератор независимо от вызываемого в качестве первого аргумента вызова.

16 голосов
/ 21 апреля 2011

вы можете перебирать вызываемый объект, возвращая константу, всегда отличающуюся от стража iter ()

g1=iter(lambda:0,1)
6 голосов
/ 21 апреля 2011

Ваша ОС может предоставлять что-то, что можно использовать как бесконечный генератор. Например, на Linux

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

очевидно, что это не так эффективно, как

for i in __import__('itertools').repeat(0)
    print i
5 голосов
/ 21 апреля 2011

Ни один, который не использует внутри себя другой бесконечный итератор, определенный как класс / функция / генератор (не-выражение, функция с yield). Выражение генератора всегда извлекается из повторяемого объекта и не делает ничего, кроме фильтрации и отображения его элементов. Вы не можете перейти от конечных предметов к бесконечным только с map и filter, вам нужно while (или for, который не заканчивается, что мы не можем использовать только с помощью *) 1006 * и конечные итераторы).

Общая информация: PEP 3142 внешне похожа, но при ближайшем рассмотрении кажется, что для нее все еще требуется условие for (поэтому для вас нет (0 while True)), т. Е. Обеспечивает только ярлык для itertools.takewhile.

3 голосов
/ 17 ноября 2017

Довольно уродливо и безумно (однако, очень смешно), но вы можете создать свой собственный итератор из выражения, используя некоторые приемы (без необходимости «загрязнять» пространство имен):

{ 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,), {}))() } 
2 голосов
/ 21 апреля 2011

Возможно, вы могли бы использовать декораторы, например, такие как:

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

Iдумаю, что это может быть улучшено, чтобы избавиться от этих уродливых ().Однако это зависит от сложности последовательности, которую вы хотите создать.Вообще говоря, если ваша последовательность может быть выражена с помощью функций, то вся сложность и синтаксический сахар генераторов могут быть скрыты внутри декоратора или функции, подобной декоратору.

...