Где вы используете функцию генераторов в вашем коде Python? - PullRequest
5 голосов
/ 29 марта 2010

Я изучил функцию генераторов и думаю, что получил ее, но я хотел бы понять, где я могу применить ее в своем коде.

Я имею в виду следующий пример, который я прочитал в книге «Справочник по Python»:

# tail -f
 def tail(f):
  f.seek(0,2) 
  while True:
   line = f.readline() 
   if not line: 
     time.sleep(0.1)
     continue
   yield line

Есть ли у вас другой эффективный пример, когда генераторы являются лучшим инструментом для работы, как tail -f?

Как часто вы используете функцию генераторов и какие функции \ части программы вы обычно применяете?

Ответы [ 4 ]

6 голосов
/ 29 марта 2010

Я часто их использую, когда внедряю сканеры (токенизаторы) или когда перебираю контейнеры данных.

Редактировать: вот демонстрационный токенизатор, который я использовал для программы выделения синтаксиса C ++:

whitespace = ' \t\r\n'
operators = '~!%^&*()-+=[]{};:\'"/?.,<>\\|'

def scan(s):
    "returns a token and a state/token id"
    words = {0:'', 1:'', 2:''} # normal, operator, whitespace
    state = 2 # I pick ws as first state
    for c in s:
        if c in operators:
            if state != 1:
                yield (words[state], state)
                words[state] = ''
            state = 1
            words[state] += c
        elif c in whitespace:
            if state != 2:
                yield (words[state], state)
                words[state] = ''
            state = 2
            words[state] += c
        else:
            if state != 0:
                yield (words[state], state)
                words[state] = ''
            state = 0
            words[state] += c
    yield (words[state], state)

Пример использования:

>>> it = scan('foo(); i++')
>>> it.next()
('', 2)
>>> it.next()
('foo', 0)
>>> it.next()
('();', 1)
>>> it.next()
(' ', 2)
>>> it.next()
('i', 0)
>>> it.next()
('++', 1)
>>> 
4 голосов
/ 29 марта 2010

Всякий раз, когда ваш код генерирует неограниченное количество значений или в более общем случае, если слишком много памяти будет использовано при генерации всего списка вначале.

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

Мое последнее знакомство с генераторами было, когда я реализовал линейную рекуррентную последовательность (LRS), например, например. последовательность Фибоначчи.

2 голосов
/ 29 марта 2010

Во всех случаях, когда у меня есть алгоритмы, которые читают что угодно, я использую исключительно генераторы.

Почему?

Слои в правилах фильтрации, отображения и сокращения намного проще в контексте нескольких генераторов.

Пример:

def discard_blank( source ):
    for line in source:
        if len(line) == 0:
            continue
        yield line

def clean_end( source ):
    for line in source:
        yield line.rstrip()

def split_fields( source ):
    for line in source;
        yield line.split()

def convert_pos( tuple_source, position ):
    for line in tuple_source:
        yield line[:position]+int(line[position])+line[position+1:]

with open('somefile','r') as source:
    data= convert_pos( split_fields( discard_blank( clean_end( source ) ) ), 0 )
    total= 0
    for l in data:
        print l
        total += l[0]
    print total

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

1 голос
/ 29 марта 2010

В целом, чтобы отделить сбор данных (который может быть сложным) от потребления. В частности:

  • для объединения результатов нескольких запросов b-дерева - часть db генерирует и выполняет запросы yield -ing записей из каждой, потребитель видит только поступающие отдельные элементы данных.
  • буферизация (упреждающее чтение) - генератор выбирает данные в блоках и выдает отдельные элементы из каждого блока. Опять же, потребитель отделен от кровавых деталей.

Генераторы также могут работать как сопрограммы. Вы можете передавать данные в , используя nextval=g.next(data) на стороне потребителя и data = yield(nextval) на стороне генератора. В этом случае генератор и его потребитель 'меняют' значения. Вы даже можете заставить yield генерировать исключение в контексте генератора: g.throw(exc) делает это.

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