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

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

Это чисто теоретический вопрос. Здесь не нужен практический ответ :)


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

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

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

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

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


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


person hugomg    schedule 20.04.2011    source источник
comment
На самом деле вам не нужно загрязнять пространство имен... просто назовите функцию my_gen, а затем выполните my_gen = my_gen().   -  person 6502    schedule 21.04.2011
comment
вы также можете использовать del _my_gen, если не хотите путать два   -  person John La Rooy    schedule 21.04.2011


Ответы (7)


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

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

person ncoghlan    schedule 21.04.2011
comment
очень интересный способ использования iter со свойством int, о котором мы много раз забываем. - person Senthil Kumaran; 21.04.2011
comment
вы можете использовать этот волшебный рецепт для имитации itertools.count: count = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1))) - person Coffee_Table; 14.08.2018
comment
Просто поясню, что здесь происходит: когда iter-функция вызывается с двумя аргументами, она ведет себя немного иначе, чем обычно: iter(callable, sentinel) -> iterator. Аргумент 1, callable вызывается для каждой итерации итератора, пока он не возвращает значение sentinel. Однако, поскольку int() всегда будет возвращать 0, мы можем вызывать int() всегда и никогда не достигнем 1. Фактически это создаст бесконечный список 0. - person Olsgaard; 14.04.2020

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

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


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

__import__("itertools").count()
person Katriel    schedule 20.04.2011
comment
Re: Repeat(x, times=∞) - нет символа для тех, кто задавался вопросом - отсутствие аргумента приводит к тому, что повтор выполняется вечно - person Mr_and_Mrs_D; 02.04.2016
comment
Проголосовал, потому что (хотя ответ ncoghlan напрямую касается вопроса ОП) это более широко применимо. - person Huw Walters; 23.01.2018
comment
Это чертовски читабельнее, чем заклинание iter(int, 1). Жаль, что у itertools нет метода endlessly(), единственной целью которого является выполнение этого; itertools.count() тоже не все так читабельно. - person BallpointBen; 04.09.2018

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

g1=iter(lambda:0, 1)
person user237419    schedule 21.04.2011
comment
Я одновременно и люблю, и ненавижу это... Мне нравится, что оно достигает того, чего я хочу, в таком небольшом количестве персонажей, но ненавижу то, что никто никогда не взглянет на него и не узнает, что он должен делать. - person ArtOfWarfare; 05.06.2017
comment
зная синтаксис iter (здесь с дополнительным часовым) и синтаксис lambda (здесь без каких-либо переданных параметров, только return 0), единственное место, где можно ненавидеть, это загадочное g1. - person Sławomir Lenart; 11.03.2019
comment
@SławomirLenart мужчины никогда этого не понимают. просто он был смущающе маленьким, поэтому я впрыснул 1 г. - person user237419; 11.03.2019

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

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

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

for i in __import__('itertools').repeat(0)
    print i
person John La Rooy    schedule 21.04.2011
comment
Решение /dev/urandom основано на появлении \n время от времени... Коварно! :) - person hugomg; 21.04.2011

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

{ 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,), {}))() } 
person Thomas Baruchel    schedule 17.11.2017
comment
@Faissaloo Действительно... Вы можете найти еще более безумное выражение на старой странице, которую я написал: baruchel.github.io/python/2018/06/20/ - person Thomas Baruchel; 21.07.2020

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

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

person Community    schedule 20.04.2011
comment
Как я и подозревал... Можем ли мы тогда быть уверены, что нет легкодоступного бесконечного генератора, которым можно злоупотреблять? (К сожалению, xrange(0,1,-1) не работает...) - person hugomg; 21.04.2011
comment
@missingno: from itertools import repeat, count, cycle, вероятно, считается легкодоступным для большинства людей. - person ncoghlan; 21.04.2011
comment
Ой, я забыл про 2-аргумент iter. Бесконечные итераторы фактически доступны как встроенные - см. Мой ответ :) - person ncoghlan; 21.04.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

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

person julx    schedule 20.04.2011
comment
OP запрашивает однострочник, а вы представляете декоратор из 10 строк с тройным вложением def и закрытием? ;) - person ; 21.04.2011
comment
@delnan Хорошо, но если вы один раз определите декоратор, у вас может быть свой один лайнер, не так ли? Насколько я понимаю, цель состоит в том, чтобы каждый дополнительный бесконечный генератор был реализован в одной строке. И вот что здесь представлено. У вас может быть (2^x), у вас может быть (x). Если вы немного улучшите его, возможно, также Фибоначчи и т. Д. - person julx; 21.04.2011
comment
Не отвечает на мой вопрос, но как же тогда не любить все эти пушистые застежки? Кстати, я почти уверен, что вы можете избавиться от лишних скобок, избавившись от seq и вернув код непосредственно к wrap. - person hugomg; 21.04.2011