itertools.cycle (итеративный) против True - PullRequest
0 голосов
/ 06 сентября 2018

Меня недавно попросили выполнить это задание (школа):

Написать генератор loop , который принимает в качестве параметра конечную итерацию и генерирует в бесконечном цикле итерацию

Так я и сделал:

import itertools
def loop(l):
    for eleme‍‌​‍‌nt in itertools.cycle(l):
        yield element

и один из моих одноклассников сделал:

def loop(l):
    while True:
​‍         for element in l:
            yield element

Я хотел бы знать, каковы основные различия между этими двумя понятиями и существует ли более «питонический» способ написать что-то простое, как это.

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Как я понимаю, цель itertools.cycle в том, что вам не нужно было бы писать это вообще:)

Самый питонский способ - просто написать loop = itertools.cycle.

Если вам действительно нужно написать это как генератор для школьного задания, вторая форма, вероятно, будет работать быстрее, потому что первая форма в основном делает то же самое, но также имеет дополнительные издержки от повторного получения значений из cycle в ваш генератор.

0 голосов
/ 06 сентября 2018

Я хотел бы знать, в чем основные различия между этими двумя ...

Основное отличие состоит в том, что эти фрагменты кода не полностью эквивалентны в поведении. Используя cycle, вы можете принять и повторить исчерпывающий итератор, тогда как цикл while не может.

>>> def gen():
...     yield 1
...     yield 2
...     
>>> def loop_it(it):
...     for element in itertools.cycle(it):
...         yield element
...         
>>> g = loop_it(gen())
>>> next(g)
1
>>> next(g)
2
>>> next(g)
1

Контрастность:

>>> def loop_while(it):
...     while True:
...         for element in it:
...             yield element
...             
>>> g = loop_while(gen())
>>> next(g)
1
>>> next(g)
2
>>> next(g)
# ... hangs forever

... и если есть более "питонический" способ написать что-нибудь простое, как это

Моя рекомендация для цикла while, в точности как написано. Если в школьном задании вас попросят написать генератор, он, вероятно, будет осужден за использование "подготовленного ранее" из itertools. Петля while также более Pythonic. Вместо этого, «itertoolsthonic» подход будет использовать цикл напрямую, например:

items = itertools.cycle(l)
# do something with `items`

Нет смысла писать дополнительные подпрограммы функции-генератора и для циклической выдачи из itertools.cycle - поскольку цикл уже является итератором, вы просто использовали бы его напрямую.

0 голосов
/ 06 сентября 2018

Вы правы, itertools.cycle не представляет большого интереса для классической петли while True.

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

generator = (x*x for x in itertools.cycle(l))

Конечно, вы всегда можете сократить текущий код на:

def loop(l):
    yield from itertools.cycle(l)

или даже:

loop = itertools.cycle
...