Рубрики
Без рубрики

Советы Python: используйте генераторы больше!

При написании функции, которая должна вернуть последовательность результатов, возвращая некоторые данные структурируют … Теги с Python, генератор, список.

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

Быстрое напоминание

Если вы знаете основы, вы можете пропустить следующий раздел. Чтобы поставить его просто, Генератор – это функция, которая возвращает значения результата один за другим. Эта функция создана с использованием ключевого слова доходность вместо вернуть Отказ

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

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

>>> def generator_func(seq):
        for num in seq:
            yield num   
>>> generator_func([1, 2, 3])

Чтобы заставить его работать, вам нужно повторить его в для петля или используя такие методы, как Далее () , Список () С Установить () , кортеж () Отказ

>>> gen = generator_func([1, 2, 3])
>>> next(gen)
1

Еще одна важная особенность – это то, что генераторы исчерпывают себя и поднимают Заставка Исключение, когда они заканчиваются ценностями, чтобы вернуться.

>>> for remaining in gen:
        print(remaining)    
2
3

Мы получили только 2 и 3 потому что 1 уже был уступлен. Здесь мы не видим никаких исключений, потому что для Петли обрабатывают их под капотом. Так что методы, такие как Список () , кортеж () , сумма () Отказ Далее () Метод не, хотя и:

>>> next(gen)
Traceback (most recent call last):
  File "", line 1, in 
    next(gen)
StopIteration

Этот конкретный генератор исчерпан. Чтобы снова использовать функцию, вам нужен новый объект генератора, который означает, что вам придется снова вызвать функцию. Теперь давайте перейдем к тому, почему вообще используют генераторы.

Почему дизайн функции как генератор?

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

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

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

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

Однако, если вы разработаете функцию обработки в качестве генератора – все, что вы возвращаете сейчас, является объектом генератора, который вы можете пережить или превращаться в структуру данных, используя такие методы, как Список () , Установить () , кортеж () Отказ И когда вам нужно что-то изменить, вы будете изменять только вызов, в то время как генератор может быть оставлен в мире.

Практический пример

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

from collections import defaultdict
from pprint import pprint

def analyze_text(file: 'I/O',) -> dict:
    """ 
    Search text data for words according to a pattern,
    then add found words to a defauldict, and count their frequency.
    """
    frequency = defaultdict(int)
    pattern = ' \n\'",.;!?()@#$%^&*`~'
    for line in file:
        for word in line.split(' '):
            word = word.strip(pattern).lower()
            if word.isalpha():
                frequency[word] += 1
    return dict(frequency)

if __name__ == '__main__':
    with open('Sherlock Holmes.txt', 'r') as file:
        frequency = analyze_text(file)
    pprint(frequency)

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

С парой незначительных изменений мы можем сделать ваш код более регулируемым:

from collections import defaultdict
from pprint import pprint

def analyze_text(file: 'I/O', 
                 pattern = ' \n\'",.;!?()@#$%^&*`~') -> str:
    """ 
    Search text data for words according to a pattern, then
    yield found words.
    """
    for line in file:
        for word in line.split(' '):
            word = word.strip(pattern).lower()
            if word.isalpha():
                yield word

if __name__ == '__main__':
    frequency = defaultdict(int)
    with open('Sherlock Holmes.txt', 'r') as file:
        for word in analyze_text(file):
            frequency[word] += 1  # do the frequency counting here
    pprint(dict(frequency))

Теперь звонивший код и Analyze_Text. Делайте две совершенно разные работы. Analyze_Text Разбивает любой пропущенный текстовый файл и возвращает каждое слово один за другим. Это не волнует то, что вы собираетесь делать с этими словами после этого, это будет работа призванного кода.

Что больше , вторая версия очень хорошо подходит для работы с обработкой огромных объемов данных, поскольку вся рабочая память требуется генераторная функция – максимальная длина одной строки ввода.

Заинтересованы для изучения более продвинутых вещей на генераторах? Проверьте мой предыдущий пост.

Надеюсь, вам понравился мой пост. Если так, пожалуйста, не забывайте любить это:)

Оригинал: “https://dev.to/v_it_aly/python-tips-use-generators-more-311c”