- Блог питониста
- Разбираемся с «with» в питоне (перевод)
- Тип contextmanager, контекстный менеджер
- Содержание:
- Синтаксис оператора контекста with :
- Как работает менеджер контекста with :
- Реализация/протокол менеджера контекста.
- contextmanager.__enter__() :
- contextmanager.__exit__(exc_type, exc_val, exc_tb) :
- Упрощенное создание менеджеров контекста.
- Программа не работает. Что делать?
- With . as — менеджеры контекста
- Оператор with в Python — менеджеры контекста
- Зачем нужны контекстные менеджеры в Python?
- Использование
- Создание наших собственных менеджеров контекста для нашего класса
- Метод __enter __()
- Метод __exit __ (exc_type, exc_val, exc_tb)
Блог питониста
Разбираемся с «with» в питоне (перевод)
18 февраля 2018 г.
Данная статья — перевод c моим небольшим дополнением, оригинал.
Часто ключевое слово with не до конца понятно даже опытным разработчикам.
Как и многие другие вещи в Python, ключевое слово with на самом деле очень просто устроено, это станет очевидно, как только вы поймете какую проблему оно решает. Посмотрите на данный код:
Здесь под «set things up» подразумевается открытие файла, подключение какого-то внешнего ресурса, а под «tear things down» — закрытие файла, отключение от внешнего ресурса. Конструкция try-finally гарантирует, что «tear things down» часть будет всегда исполнена, даже если код, делающий что-либо вызовет ошибку или не завершится.
Если это часто ипользуется, то было бы удобно вынести код “set things up” и “tear things down” в библиотечную функцию, чтобы легко ее использовать. Конечно, вы можете сделать что-то вроде:
Но это немного многословно, особенно если вам нужно изменять локальные переменные. Другой подход заключается в использовании генератора, а затем нужно использовать for-in:
Но yield нельзя было использовать внутри try-finally в 2.4 и раньше. И немного странно использовать loop для чего-то, что вы хотите выполнить один раз.
Поэтому, после рассмотрения нескольких вариантов, Гвидо Ван Россум и python-dev команда наконец решили использовать объект вместо генератора, чтобы контролировать поведение данного кода:
Теперь, когда «with» выражение исполняется, Python исполняет выражение, вызывает метод __enter__ с полученным значением (которое называется «context guard»), затем присваивает переменной переданной словом as (в данном случае thing) то, что возвращает метод __enter__. Далее, Python исполняет тело (в данное случае some code), и в любом случае вызывает метод __exit__.
В добавок, __exit__ может подавить исключение, вернуть вместо него True. Например, этот __exit__ заменяет TypeError, но разрешает все другие исключения:
Источник
Тип contextmanager, контекстный менеджер
Оператор with в Python поддерживает концепцию контекста среды выполнения, определенного контекстным менеджером. Типичные области применения контекстных менеджеров включают сохранение и восстановление различных типов глобального состояния, блокировку и разблокировку ресурсов, закрытие открытых файлов и т. д.
Содержание:
Синтаксис оператора контекста with :
Выражение EXPRESSION , непосредственно следующее за ключевым словом with является «выражением контекста», так как это выражение обеспечивает основной ключ к среде выполнения, которую менеджер контекста устанавливает для продолжительности тела выражения.
Как работает менеджер контекста with :
- Выражение контекста (выражение, указанное в EXPRESSION ) оценивается для получения менеджера контекста.
- Менеджер контекста загружает метод __enter__() для последующего использования.
- Менеджер контекста загружает метод __exit__() для последующего использования.
- Менеджер контекста вызывает метод __enter__() .
- Если TARGET была включена в оператор with , то ей присваивается возвращаемое значение из метода __enter__() .
Обратите внимание, что оператор with гарантирует, что если метод __enter__() возвращается без ошибки, то всегда будет вызываться метод __exit__() . Таким образом, если ошибка возникает во время присваивания значения через оператор as , то она будет обрабатываться так же, как и ошибка, возникающая внутри with . - Последовательность команд выполнена.
- Вызван метод __exit__() . Если исключение вызвало выход из последовательности команд, то его тип exc_type , значение exc_val и информация о трассировке exc_tb передаются в качестве аргументов __exit__() . В противном случае предоставляется три аргумента None .
Если последовательность команд была завершена из-за исключения, а возвращаемое значение из метода __exit__() было False , то исключение вызывается повторно. Если возвращаемое значение было True , то исключение подавляется и выполнение продолжается с оператора, следующего за оператором with .
Если последовательность команд была завершена по любой причине, кроме исключения, то возвращаемое значение из __exit__() игнорируется, и выполнение продолжается.
При наличии нескольких контекстных менеджеров, то они обрабатываются так, как если бы несколько операторов with были вложенными:
Реализация/протокол менеджера контекста.
Протокол контекстных менеджеров реализован с помощью пары методов, которые позволяют определяемым пользователем классам определять контекст среды выполнения, который вводится до выполнения тела инструкции и завершается при завершении инструкции:
contextmanager.__enter__() :
Метод contextmanager.__enter__() вводит контекст среды выполнения и возвращает либо себя, либо другой объект, связанный с контекстом среды выполнения. Значение, возвращаемое этим методом, привязывается к идентификатору в предложении as оператора with , использующего этот контекстный менеджер.
Ярким примером контекстного менеджера, который возвращает себя, является объект file . Файловые объекты возвращают себя из __enter__() , чтобы разрешить использование встроенной функции open() в качестве контекстного выражения в операторе with .
contextmanager.__exit__(exc_type, exc_val, exc_tb) :
Метод contextmanager.__exit__() предоставляет выход из контекста среды выполнения и возвращает логический флаг, указывающий, следует ли подавлять любое возникшее исключение. При возникновении исключения во время выполнения тела оператора with , аргументы содержат тип исключения exc_type , значение exc_val и информацию о трассировке exc_tb . В противном случае все три аргумента — это None .
Если у метода contextmanager.__exit__() установить возвращаемое значение в return True , то это приведет к тому, что оператор with будет подавлять возникающие исключения внутри себя и продолжит выполнение с оператора, непосредственно следующим за оператором with . В противном случае исключение exc_type продолжает распространяться после завершения выполнения этого метода. Исключения, возникающие во время выполнения этого метода, заменят все исключения, возникшие в теле оператора with .
Передаваемое исключение exc_type никогда не следует повторно вызывать явно, вместо этого метод contextmanager.__exit__() должен возвращать return False , чтобы указать, что метод завершился успешно и не хочет подавлять возникшее исключение. Это позволяет коду управления контекстом легко определять, действительно ли метод contextmanager.__exit__() потерпел неудачу.
Упрощенное создание менеджеров контекста.
Поддержка упрощенного создания менеджеров контекста предоставляется модулем contextlib .
Многие контекстные менеджеры, например, файлы и контексты на основе генераторов будут одноразовыми объектами. После вызова метода __exit__() менеджер контекста больше не будет находиться в работоспособном состоянии (например, файл был закрыт или базовый генератор завершил выполнение).
Необходимость создания нового объекта менеджера контекста для каждого оператора with — это самый простой способ избежать проблем с многопоточным кодом и вложенными операторами, пытающимися использовать один и тот же контекстный менеджер. Не случайно, что все стандартные менеджеры контекста модуля contextlib , поддерживающие повторное использование, происходят из модуля threading и все они уже разработаны для решения проблем, создаваемых потоковым и вложенным использованием.
Это означает, что для сохранения менеджера контекста с определенными аргументами инициализации, которые будут использоваться в нескольких операторах with , как правило, необходимо будет сохранить его в вызываемом объекте с нулевым аргументом, который затем вызывается в выражении контекста каждого оператора, а не кэшировать непосредственно менеджер контекста. Если это ограничение не применяется, это должно быть ясно указано в документации соответствующего контекстного менеджера.
Источник
Программа не работает. Что делать?
Моя программа не работает! Что делать? В данной статье я постараюсь собрать наиболее частые ошибки начинающих программировать на python 3, а также расскажу, как их исправлять.
Проблема: Моя программа не запускается. На доли секунды появляется чёрное окошко, а затем исчезает.
Причина: после окончания выполнения программы (после выполнения всего кода или при возникновении исключения программа закрывается. И если вы её вызвали двойным кликом по иконке (а вы, скорее всего, вызвали её именно так), то она закроется вместе с окошком, в котором находится вывод программы.
Решение: запускать программу через IDLE или через консоль.
Проблема: Не работает функция input. Пишет SyntaxError.
Причина: Вы запустили Python 2.
Проблема: Где-то увидел простую программу, а она не работает.
Причина: Вам подсунули программу на Python 2.
Решение: Прочитать об отличиях Python 2 от Python 3. Переписать её на Python 3. Например, данная программа на Python 3 будет выглядеть так:
Проблема: TypeError: Can’t convert ‘int’ object to str implicitly.
Причина: Нельзя складывать строку с числом.
Решение: Привести строку к числу с помощью функции int(). Кстати, заметьте, что функция input() всегда возвращает строку!
Проблема: SyntaxError: invalid syntax.
Причина: Забыто двоеточие.
Проблема: SyntaxError: invalid syntax.
Причина: Забыто равно.
Проблема: NameError: name ‘a’ is not defined.
Причина: Переменная «a» не существует. Возможно, вы опечатались в названии или забыли инициализировать её.
Решение: Исправить опечатку.
Проблема: IndentationError: expected an indented block.
Причина: Нужен отступ.
Проблема: TabError: inconsistent use of tabs and spaces in indentation.
Причина: Смешение пробелов и табуляции в отступах.
Решение: Исправить отступы.
Проблема: UnboundLocalError: local variable ‘a’ referenced before assignment.
Причина: Попытка обратиться к локальной переменной, которая ещё не создана.
Проблема: Программа выполнилась, но в файл ничего не записалось / записалось не всё.
Причина: Не закрыт файл, часть данных могла остаться в буфере.
Проблема: Здесь может быть ваша проблема. Комментарии чуть ниже 🙂
Источник
With . as — менеджеры контекста
Конструкция with . as используется для оборачивания выполнения блока инструкций менеджером контекста. Иногда это более удобная конструкция, чем try. except. finally.
Синтаксис конструкции with . as:
Теперь по порядку о том, что происходит при выполнении данного блока:
- Выполняется выражение в конструкции with . as.
- Загружается специальный метод __exit__ для дальнейшего использования.
- Выполняется метод __enter__. Если конструкция with включает в себя слово as, то возвращаемое методом __enter__ значение записывается в переменную.
- Выполняется suite.
- Вызывается метод __exit__, причём неважно, выполнилось ли suite или произошло исключение. В этот метод передаются параметры исключения, если оно произошло, или во всех аргументах значение None, если исключения не было.
Если в конструкции with — as было несколько выражений, то это эквивалентно нескольким вложенным конструкциям:
Для чего применяется конструкция with . as? Для гарантии того, что критические функции выполнятся в любом случае. Самый распространённый пример использования этой конструкции — открытие файлов. Я уже рассказывал об открытии файлов с помощью функции open, однако конструкция with . as, как правило, является более удобной и гарантирует закрытие файла в любом случае.
Гарантирует, что файл будет закрыт вне зависимости от того, что введёт пользователь.
Источник
Оператор with в Python — менеджеры контекста
Оператор Python with очень полезен. Он появился с Python 2.5, и теперь это вездесущая функция, используемая почти каждым приложением.
Самое полезное (фактически единственное!) Он открывает и освобождает ресурсы.
По сути, он обрабатывает открытие и закрытие любых ресурсов, которые могут вам понадобиться для определенной части программы, а затем автоматически закрывает ее.
Зачем нужны контекстные менеджеры в Python?
Рассмотрим сценарий, в котором вы выполняете обработку файлов. В других языках, таких как C, мы должны вручную открывать и закрывать файл следующим образом:
Оператор with теперь автоматически это делает, поэтому вам не нужно каждый раз закрывать файл вручную. У оператора with есть контекст (блок), в котором он действует. Это как объем заявления.
Когда программа выходит из этого контекста, with автоматически закрывается ваш файл. Из-за этого with часто называют диспетчером контекста. Таким образом, можно использовать те же процедуры обработки файлов.
Обратите внимание, насколько это интуитивно понятно. Оператор Python with всегда будет закрывать файл в конце, даже если программа завершилась ненормально даже в контексте или блоке.
Эта функция безопасности рекомендуемый выбор для всех программистов.
Использование
Теперь, несмотря на то, что существует множество классов, в которых реализована возможность использования with , нам интересно посмотреть, как она работает, чтобы мы могли написать ее сами!
- Во-первых, оператор with сохраняет ссылку на объект в объекте контекста.
Объект контекста — это объект, который содержит дополнительную информацию о своем состоянии, такую как модуль или область видимости и т. д. Это полезно, поскольку мы можем сохранять или восстанавливать состояние этого объекта.
А теперь идем дальше. После создания объекта контекста он вызывает метод __enter__ dunder для объекта.
- Оператор __enter__ фактически выполняет работу по открытию ресурсов для объекта, таких как файл или сокет. Обычно при необходимости мы можем реализовать его для сохранения состояния объекта контекста.
Теперь помните ключевое слово as ? Это фактически возвращает объект контекста. Поскольку нам нужен объект, возвращаемый функцией open(), мы используем ключевое слово as для получения объекта контекста.
Использование as необязательно, особенно если у вас есть ссылка на исходный объект контекста в другом месте.
После этого мы входим во вложенный блок операторов.
После того, как вложенный блок закончился, ИЛИ, если в нем есть исключение, программа всегда выполняет __exit__ для объекта контекста.
Это первая функция безопасности, о которой мы говорили ранее. Итак, что бы ни случилось, мы всегда будем использовать __exit__ для освобождения ресурсов и выхода из контекста.
Наконец, если возможно, __exit__ может быть реализован так, чтобы восстановить состояние объекта контекста, чтобы он вернулся в то состояние, к которому он принадлежал.
Чтобы было понятнее, давайте рассмотрим пример создания нашего собственного диспетчера контекста для класса.
Создание наших собственных менеджеров контекста для нашего класса
Рассмотрим приведенный ниже класс, для которого у нас будет собственный диспетчер контекста для обработки файлов.
Внимательно изучите методы класса. У нас есть метод __init__ для нашего обработчика, который устанавливает начальное состояние объектов контекста и соответствующих переменных.
Теперь метод __enter__ dunder сохраняет состояние объекта и открывает файл. Теперь мы внутри блока.
После выполнения блока диспетчер контекста наконец выполняет __exit__ , при этом восстанавливается исходное состояние объекта контекста и файл закрывается.
Хорошо, похоже, у нас нет ошибок. Мы только что реализовали собственные контекстные менеджеры для нашего Custom Class. Теперь есть другой подход к созданию диспетчера контекста, который использует генераторы.
Однако это обычно не рекомендуется, если вы точно не знаете, что делаете, поскольку вы должны сами обрабатывать исключения.
Есть два разных метода для менеджера контекста. Эти методы —
Метод __enter __()
Метод __enter __() используется для входа в контекст времени выполнения. Он вернет либо текущий объект, либо другой связанный объект. Возвращаемое значение привязывается к идентификатору в качестве предложения оператора with.
Метод __exit __ (exc_type, exc_val, exc_tb)
Метод __exit __() используется для возврата результата логического типа. Это указывает на любое исключение, которое произошло. Если есть одно исключение для оператора with, оно перейдет в конец блока.
Источник