В чем преимущество использования генератора в этом случае? - PullRequest
2 голосов
/ 28 мая 2011

Я изучаю генератор Python из этого слайда: http://www.dabeaz.com/generators/Generators.pdf
В нем есть пример, который можно описать так:
У вас есть файл журнала с именем log.txt, напишите программу насмотреть его содержимое, если к нему добавлена ​​новая строка, распечатать их.Два решения:

1. with generator:  

    import time

    def follow(thefile):
        while True:
            line = thefile.readline()
            if not line:
                time.sleep(0.1)
                continue
            yield line

    logfile = open("log.txt")
    loglines = follow(logfile)
    for line in loglines:
        print line


2. Without generator:  

    import time

    logfile = open("log.txt")

    while True:
        line = logfile.readline()
        if not line:
            time.sleep(0.1)
            continue
        print line

В чем преимущество использования генератора здесь?

Ответы [ 5 ]

5 голосов
/ 28 мая 2011

Если у вас есть только молоток, все выглядит как гвоздь

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

Но концептуально версия генератора разделяет функциональность, а функция follow предназначена для инкапсуляции непрерывного чтения из файла в ожидании нового ввода. Что позволяет вам делать что-либо в цикле с новой строкой, которую вы хотите. Во второй версии код, который нужно прочитать из файла и распечатать, смешан с циклом управления. Это не может быть проблемой в этом небольшом примере, но вы можете подумать об этом.

1 голос
/ 19 июля 2017

Функция генератора определяется как обычная функция, но всякий раз, когда ей нужно сгенерировать значение, она делает это с помощью ключевого слова yield, а не return. Его главное преимущество заключается в том, что он позволяет своему коду генерировать серии значений во времени, а не вычислять их сразу и отправлять обратно как список. Например

# A Python program to generate squares from 1
# to 100 using yield and therefore generator

# An infinite generator function that prints
# next square number. It starts with 1
def nextSquare():
    i = 1;

    # An Infinite loop to generate squares 
    while True:
        yield i*i                
        i += 1  # Next execution resumes 
                # from this point     

# Driver code to test above generator 
# function
for num in nextSquare():
    if num > 100:
         break   
    print(num)

Return отправляет указанное значение обратно своему вызывающему, тогда как Yield может генерировать последовательность значений. Мы должны использовать yield, когда хотим перебрать последовательность, но не хотим сохранять всю последовательность в памяти.

1 голос
/ 28 мая 2011

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

import time

def follow(file_name):
    with open(file_name, 'rb') as f:
        for line in f:
            if not line:
                time.sleep(0.1)
                continue
            yield line

loglines = follow(logfile)
first_line = loglines.next()
second_line = loglines.next()
for line in loglines:
    print line

Прежде всего я открыл файл с помощью диспетчера контекста (оператор with, который автоматически закрывает файл, когда вы закончите сэто, или в порядке исключения).Далее в нижней части я продемонстрировал использование метода .next(), который позволяет вам шаг за шагом проходить вручную.Иногда это может быть полезно, если вам нужно вырвать логику из простого цикла for item in gen.

0 голосов
/ 29 мая 2011

Хотя ваш пример может быть немного проще, чтобы полностью использовать преимущества генераторов, я предпочитаю использовать генераторы для инкапсуляции генерации любых данных последовательности, где также есть какая-то фильтрация данных. Он хранит код «что я делаю с данными» отдельно от кода «как я получаю данные».

0 голосов
/ 28 мая 2011

В идеале большинство циклов примерно имеют форму:

for element in get_the_next_value():
     process(element)

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...