Всякий раз, когда я пишу несколько строк на python, у меня в голове всегда возникает вопрос, есть ли лучший способ написать этот код! Лучше не в смысле алгоритмического подхода, хотя это имеет значение, на самом деле это имеет значение больше всего, например, сокращение временных или пространственных сложностей или и того, и другого! Это то, что дает вашему подходу преимущество по сравнению с тем, как другие собираются решать ту же проблему. Но следующий важный момент, который выпадает сразу после этого, - пишете ли вы так, как должно быть?
Короче говоря, есть ли более питонический (и, конечно, лучший) способ написать тот же код?
Допустим, вы должны были записать некоторые данные json в файл.
Очевидный подход - открыть файл, записать данные json в файл и закрыть его. Этот простой интуитивно понятный подход был хорош только до тех пор, пока не было исключений.
Допустим, строка номер 16 вызывает ошибку, возможно, data
не является допустимым json. В таком случае дальнейшее выполнение останавливается, и программа немедленно останавливается. Вы должны заметить здесь одну вещь: close()
не был вызван на 18-й строке. В результате произошла утечка дескриптора файла, и существует большая вероятность того, что данные будут повреждены. Это ужасная проблема, особенно если вы работаете с файлами, которые важны для системы или бизнес-организации, на которую вы работаете.
Так что же делать, чтобы обойти эту проблему? Одно из возможных решений - использовать блок try-except, который не только обнаружит ошибку, но и в любом случае у нас есть возможность явно закрыть файл.
Однако размещение вашего кода в блоке try-except в большинстве случаев выглядит некрасиво, и лучшей и красивой альтернативой является использование context-manager.
Довольно простой синтаксис выглядит как
with context_manager as something: # do anything with something pass
Это эквивалентно блоку try-finally.
something = expression something.__enter__() try: # do anything with something pass finally: something.__exit__()
Наша функция, переписанная с помощью оператора with
, теперь выглядит более чистой.
Нам не нужно явно закрывать файл, обо всем этом позаботится оператор with
. Конечно, что-то происходит под капотом. Чтобы разобраться в них более подробно, давайте создадим собственный контекстный менеджер.
Наш настраиваемый контекстный менеджер - это класс со (в частности) следующими двумя методами:
__enter__()
__exit__()
__enter__()
вызывается во время вызова диспетчера контекста, а метод __exit__()
вызывается для завершения кода, когда выполнение блока with
завершено, то есть в конце блока. Таким образом, все, что, по вашему мнению, должно выполняться на этапе инициализации блока with
, должно находиться внутри тела __enter__()
. __exit__()
должен содержать весь код очистки, который вы хотите выполнить в конце блока with
. Код в теле __exit__()
выполняется даже в тех случаях, когда мы обнаруживаем ошибки во время выполнения. Это гарантирует гарантированное выполнение действий по очистке, таких как закрытие файла в предыдущем случае, даже если во время вызовов json.loads()
или json.dump()
произошла ошибка.
Следует помнить, что переменные, определенные внутри блока with
, имеют локальную область видимости, однако сам диспетчер контекста не имеет локальной области (с блоком with
) и, следовательно, может использоваться повторно.
Менеджеры контекста могут использоваться для других целей, а не для простого ввода-вывода файлов, таких как открытие и закрытие сокетов, реализация функций настройки и удаления во время тестирования и тому подобное, о чем я не знаю.
Надеюсь, вам понравилось читать эту статью. Если у вас есть какие-либо предложения, пожалуйста, дайте мне знать в комментариях. Наконец, если вы нашли эту статью стоящей вашего времени, нажмите кнопку Рекомендовать, и я думаю, что кнопка следовать вызовет ревность, если вы оставите ее нетронутой. Спасибо за чтение, надеюсь, вы узнали что-то новое ;-)