Подтвердить что ты не робот

Когда использовать "с" в python

Я видел этот вопрос, и я понимаю, когда вы захотите использовать with foo() as bar:, но я не понимаю, когда вы просто хотите сделать:

bar = foo()
with bar:
   ....

Разве это не просто устраняет преимущества сбрасывания при использовании with ... as, или я не понимаю, что происходит? Почему кто-то хочет использовать только with?

4b9b3361

Ответ 1

Чтобы развернуть бит в ответе @freakish, with гарантирует вход и выход из контекста. Что это за контекст? Ну, это "независимо от того, что вы делаете". Некоторые очевидные:

  • блокировки: вы берете блокировку, манипулируете некоторыми данными и освобождаете блокировку.
  • внешние файлы/потоки: вы открываете файл, читаете или записываете его и закрываете.
  • записи базы данных: вы найдете запись (которая обычно также блокирует ее), используйте некоторые поля и, возможно, изменить их и отпустить запись (которая также разблокирует ее).

Менее очевидные могут включать даже определенные виды захвата исключений: вы можете поймать деление на ноль, сделать некоторую арифметику, а затем перестать ее ловить. Конечно, это встроено в синтаксис Python: try... except как блок! И, фактически, with - это просто частный случай механизмов try/except/finally Python (технически, try/finally, завернутый вокруг другого блока try, см. Комментарии).

Часть as блока with полезна, когда контекстная запись предоставляет некоторые значения, которые вы хотите использовать внутри блока. В случае записи файла или базы данных очевидно, что вам нужен только что открытый поток или только что полученная запись. В случае обнаружения исключения или блокировки структуры данных может не потребоваться получение значения из контекстной записи.

Ответ 2

Например, если вы хотите использовать Lock():

from threading import Lock
myLock = Lock()
with myLock:
   ...

Вам действительно не нужен объект Lock(). Вам просто нужно знать, что он включен.

Ответ 3

Используя with без as, вы все равно получите то же самое; он просто не дает вам новый локальный объект, представляющий контекст.

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

Например, с объектом Lock вы должны уже иметь объект для блока with, чтобы быть полезным, поэтому, даже если вам это нужно в блоке, нет причин переписывать его другому имени, То же самое верно, если вы используете contextlib.closing для объекта, который не является диспетчером контекста, у вас уже есть сам объект, поэтому кто заботится о том, что closing дает?

С чем-то вроде sh.sudo нет даже объекта, для которого вы бы использовали, период.

Есть также случаи, когда точка диспетчера контекста находится там, чтобы запереть и автоматически восстановить какое-то состояние. Например, вы можете написать termios.tcsetattr -stasher, поэтому вы можете вызвать tty.setraw() внутри блока. Вам все равно, как выглядит объект закладок, вам все равно, что он автоматически восстанавливается.

decimal.localcontext может работать любым из этих способов: вы можете передать ему объект, который у вас уже есть (и, следовательно, не нуждаетесь в новом имени), или передать ему неназванный временный объект или просто зачерпнуть текущий контекст будет автоматически восстановлен. Но в любом из этих случаев.

Есть несколько гибридных случаев, когда вам иногда нужен контекст, иногда вы этого не делаете. Например, если вы хотите, чтобы транзакция базы данных выполнялась автоматически, вы можете написать with autocommit(db.begin()):, потому что вы не будете получать доступ к ней внутри блока. Но если вы хотите автоматическое откат, если вы явно не зафиксируете его, вы, вероятно, напишите with autorollback(db.begin()) as trans:, чтобы вы могли trans.commit() внутри блока. (Конечно, часто вам нужна транзакция, которая совершает обычный выход и откатывается от исключения, как в PEP 343 transaction example. Но я не мог придумать лучший гибридный пример здесь...)

PEP 343 и его предшественники (PEP 310, PEP 340 и другие вещи, связанные с 343) объясняют все это в некоторой степени, но понятно, что вы не выбрали бы это на случайном прочтении - там столько информации, которая не имеет отношения к делу, и в основном это объясняет общий обзор мили, а затем детали уровня реализации, пропуская все между ними.