Код примера закрытия 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
чтение в файле правил по строкам в цикле
строка за строкой в цикле
петли
Это обеспечит производительность через пол. Прочитайте один раз, примените много раз.