Чи є вираз для нескінченного генератора?


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яке ми багато разів забуваємо.
Сентітіл Кумаран

3
Ви можете використовувати цей магічний рецепт для імітації itertools.count:count = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1)))
Кава_Таблиця

1
Просто пояснити , що тут відбувається: Коли iter-Функції викликається з двома аргументами, вона поводиться трохи інакше , ніж зазвичай: iter(callable, sentinel) -> iterator. Аргумент 1 callableвикликається для кожної ітерації ітератора, поки він не поверне значення sentinel. Однак, як int()завжди повернемось 0, ми можемо зателефонувати int()назавжди і ніколи не досягнемо 1. Це фактично створить нескінченний список 0"s
Olsgaard

217

itertools забезпечує три безмежні генератори:

Я не знаю жодного іншого в стандартній бібліотеці.


Оскільки ви попросили вкладиша:

__import__("itertools").count()

18
Re: повторити (x, разів = ∞) - немає символу для того, хто б задумався - опускання аргументу робить повторний біг назавжди
Mr_and_Mrs_D

Запропоновано, оскільки (хоча відповідь ncoghlan безпосередньо стосується питання ОП), це є більш загальним.
Хью Уолтерс

Це чорт набагато більш читабельний, ніж 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г.
користувач237419

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). Вираз генератора завжди витягується з іншого ітерабельного і не робить нічого, крім фільтрування та відображення його елементів. Ви не можете переходити від кінцевих предметів до нескінченних лише тим, 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
ОП просить придбати oneliner, а ви представляєте 10-лінійний декоратор із трійковим вкладом defта закриттям? ;)

2
@delnan Добре, але якщо ви визначите декоратора один раз, ви можете мати один вкладиш, чи не так? Як я розумію, мета полягає в тому, щоб кожен додатковий нескінченний генератор був реалізований в одному рядку. І ось що представлено тут. Ви можете мати (2^x), можете мати (x). Якщо ви трохи вдосконалите його, можливо, також
поле

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