Код примера закрытия Python

Я изучаю Python, используя Dive Into Python 3. Мне это нравится, но я не понимаю пример используемый для введения Closures в разделе 6.5.

Я имею в виду, я вижу, как это работает, и я думаю, что это действительно здорово. Но я не вижу никакой реальной выгоды: мне кажется, что один и тот же результат может быть достигнут простым чтением в файле правил строки за строкой в ​​цикле и выполнением поиска/замены для каждой строки.

Помог ли кто-нибудь мне:

  • либо понять, почему использование закрытий в этом примере улучшает код (например, проще поддерживать, расширять, повторно использовать или отлаживать?)

  • или предложите источник некоторых других примеров кода в реальной жизни, где действительно светятся замыкания?

Спасибо!

Ответы

Ответ 1

Декораторы - пример закрытия. Например,

def decorate(f):
    def wrapped_function():
        print("Function is being called")
        f()
        print("Function call is finished")
    return wrapped_function

@decorate
def my_function():
    print("Hello world")

my_function()

Функция wrapped_function является замыканием, поскольку она сохраняет доступ к переменным в своей области - в частности, параметр f, исходная функция. Закрытие - это то, что позволяет вам получить к нему доступ.

Закрытие также позволяет сохранить состояние через вызовы функции, не прибегая к классу:

def make_counter():
    next_value = 0
    def return_next_value():
        nonlocal next_value
        val = next_value
        next_value += 1
        return val
    return return_next_value

my_first_counter = make_counter()
my_second_counter = make_counter()
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())

Кроме того, связанные методы являются технически закрытыми (хотя они, вероятно, реализованы по-разному). Связанные методы - это функции класса с классом, испеченным в:

import sys
w = sys.stdout.write
w("Hello\n")

w по существу является замыканием со ссылкой на объект sys.stdout.

Наконец, я не читал эту книгу, но быстро прочитал главу, которую вы связали, и я очень не впечатлен - это настолько ужасно круто, что это бесполезно, как объяснение закрытия.

Ответ 2

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

Ответ 3

здесь использование замыкания, получить настройки:

def confmaker():
   cf=ini_conf()
   def clo(*args):
      return cf.get(*args)
   return clo

cfget=confmaker()

cfget(...)

здесь ini_conf вызывается только один раз. В моем понимании, замыкания избегают глобальных переменных (например, cf) и делают использование простым.

Ответ 4

Нильс-Бом пишет (с изменениями):

То же самое можно было бы получить, просто прочитав в файле правил строку за строкой в ​​цикле и выполнив поиск/замену для каждой строки.

И на самом деле это то, что по существу выполнено в разделе 6.5, где правила помещаются в файл plural4-rules.txt. С правилами теперь как строки они могут поддерживаться внутри файла, а наш код отделяет данные от элемента управления. Это упрощает управление и обслуживание проекта.

Вопрос Нильса побудил меня наметить разработку главы 6, чтобы понять, что именно пытался доказать автор. Есть много уроков, которые нужно изучать при разработке, и речь идет не только о закрытии, но и о лучших методах кодирования.

Упражнение помогло мне понять, как генераторы могут использоваться для замены альтернативных, менее абстрактных и более запутанных реализаций. Разработка материала с 6.2 по 6.6 является достаточно образовательной, чтобы набросать здесь.

Итак, я начинаю со второго пункта Нильса относительно разложения правил на отдельные функции в 6.3 как segue в эскиз:

Почему использование закрытий в этом примере улучшает код?

Автор заявляет в этот момент:

Добавлял ли этот уровень абстракции? Ну, еще нет.

По-прежнему существуют разделы 6.4-6.6. История закрытия, и в этом случае создание генератора плюрализации выполняется шаг за шагом, начиная с жестко закодированных правил в модуле, называемом plural (существительное). Итак, начиная с первого соответствующего раздела и обобщая наш путь до конца главы, мы имеем следующее.

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

6,3. Список функций: Абстрагирует правила, жестко закодированные в функции множественного числа, нескольким автономным функциям. Это "ступенька" к следующему разделу. Но это также демонстрирует, что существует важное различие между использованием match_sxz() и match_sxz.

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

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

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

Это означает, что все функции множественного числа() должны делать, и это должно делать все функции множественного числа().

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

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

Ответ 5

чтение в файле правил по строкам в цикле

строка за строкой в ​​цикле

петли

Это обеспечит производительность через пол. Прочитайте один раз, примените много раз.