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


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если не хотите путать их
— Джон Ла Рой

Ответы:


133
for x in iter(int, 1): pass
  • Два аргумента iter= вызываемый без аргументов + контрольное значение
  • int() всегда возвращается 0

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


3
очень интересный способ использования iterсвойства, о intкотором мы много раз забываем.
— Senthil Kumaran

3
вы можете использовать этот волшебный рецепт для имитации itertools.count:count = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1)))
— Coffee_Table

1
Просто объяснить , что здесь происходит: Когда iter-функции вызывается с двумя аргументами, она ведет себя немного иначе , чем обычно: iter(callable, sentinel) -> iterator. Аргумент 1 callableвызывается для каждой итерации итератора, пока он не вернет значение sentinel. Однако, как int()всегда будет возвращаться 0, мы можем назвать int()вечно и никогда не достигнет 1. Это будет фактически производить бесконечный список 0«s
— Olsgaard

217

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

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


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

__import__("itertools").count()

18
Re: repeat (x, times = ∞) - нет ∞символа для того, кто задался вопросом - отсутствие аргумента приводит к повторному запуску навсегда
— Mr_and_Mrs_D 02

Проголосовали, потому что (в то время как ответ ncoghlan напрямую касается вопроса OP) это более широко применимо.
— Huw Walters

Это чертовски удобнее, чем iter(int, 1)заклинание. Жаль, itertoolsчто нет endlessly()метода, единственная цель которого - это делать; itertools.count()тоже не все так читабельно.
— BallpointBen

19

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

g1=iter(lambda:0, 1)

8
Я и люблю, и ненавижу это ... Мне нравится, что он выполняет то, что я хочу, в таком небольшом количестве персонажей, но ненавижу то, что никто никогда не будет смотреть на это и знать, что он должен делать.
— ArtOfWarfare

1
зная синтаксис iter(здесь с дополнительным часовым) и синтаксис lambda(здесь без каких-либо переданных параметров, просто return 0), единственное место, где можно ненавидеть, - это таинственность g1.
— Славомир Ленарт

@ 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 зависит от того, \nпоявляются ли они время от времени ... Коварный! :)
— hugomg

5

Ни один, который внутренне не использует другой бесконечный итератор, определенный как класс / функция / генератор (не -выражение, функция с yield). Выражение генератора всегда извлекается из итерируемого объекта anoter и ничего не делает, кроме фильтрации и сопоставления своих элементов. Вы не можете перейти от конечных элементов к бесконечным с помощью только 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

1
Ой, я забыл про 2-аргумент iter. Бесконечные итераторы фактически доступны как встроенные - см. Мой ответ :)
— ncoghlan

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/…
— Thomas Baruchel

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 запрашивает одинарный лайнер, а вы представляете декоратор из 10 строк с тройным вложением defи закрытием? ;)

2
@delnan Хорошо, но если вы определите декоратор один раз, у вас будет свой однострочник, не так ли? Насколько я понимаю, цель состоит в том, чтобы каждый дополнительный бесконечный генератор был реализован в одной строке. И это то, что здесь представлено. Вы можете иметь (2^x), можете иметь (x). Если вы немного улучшите его, возможно, также фибоначчи и т. Д.
— julx

Не отвечает на мой вопрос, но как же тогда вам не полюбить все эти пушистые застежки? Кстати, я почти уверен, что вы можете избавиться от лишних скобок, избавившись от seqкода и wrap
— сделав
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.