Что такое питон "с", предназначенный для?
Я впервые встретил инструкцию Python with
. Я несколько лет использовал Python и даже не знал о его существовании! Учитывая его несколько неясный статус, я подумал, что стоит подумать:
- Что такое оператор Python
with
предназначен для использования?
- Что делать
вы используете его для?
- Есть ли какие-либо
Мне нужно знать, или
общие анти-шаблоны, связанные с
его использование? Любые случаи, когда лучше использовать
try..finally
чем with
?
- Почему он не используется более широко?
- Какие стандартные классы библиотек совместимы с ним?
Ответы
Ответ 1
-
Я считаю, что на меня уже ответили другие пользователи, поэтому я только добавляю их для полноты: инструкция with
упрощает обработку исключений путем инкапсуляции общих задач подготовки и очистки в так называемом контекстные менеджеры. Более подробную информацию можно найти в PEP 343. Например, оператор open
представляет собой менеджер контекста сам по себе, который позволяет открывать файл, держать его открытым, пока выполнение выполняется в контексте оператора with
, где вы его использовали, и закрывайте его как можно скорее когда вы покидаете контекст, независимо от того, покинули ли вы его из-за исключения или во время регулярного потока управления. Таким образом, оператор with
можно использовать способами, аналогичными образу RAII на С++: некоторый ресурс приобретается оператором with
и выпущен когда вы покидаете контекст with
.
-
Некоторые примеры: открытие файлов с помощью with open(filename) as fp:
, получение блокировок с использованием with lock:
(где lock
- это экземпляр threading.Lock
). Вы можете также создать свои собственные менеджеры контекста, используя декоратор contextmanager
от contextlib
. Например, я часто использую это, когда мне нужно временно изменить текущий каталог, а затем вернуться туда, где я был:
from contextlib import contextmanager
import os
@contextmanager
def working_directory(path):
current_dir = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(current_dir)
with working_directory("data/stuff"):
# do something within data/stuff
# here I am back again in the original working directory
Вот еще один пример, который временно перенаправляет sys.stdin
, sys.stdout
и sys.stderr
в другой дескриптор файла и восстанавливает их позже:
from contextlib import contextmanager
import sys
@contextmanager
def redirected(**kwds):
stream_names = ["stdin", "stdout", "stderr"]
old_streams = {}
try:
for sname in stream_names:
stream = kwds.get(sname, None)
if stream is not None and stream != getattr(sys, sname):
old_streams[sname] = getattr(sys, sname)
setattr(sys, sname, stream)
yield
finally:
for sname, stream in old_streams.iteritems():
setattr(sys, sname, stream)
with redirected(stdout=open("/tmp/log.txt", "w")):
# these print statements will go to /tmp/log.txt
print "Test entry 1"
print "Test entry 2"
# back to the normal stdout
print "Back to normal stdout again"
И, наконец, еще один пример, который создает временную папку и очищает ее при выходе из контекста:
from tempfile import mkdtemp
from shutil import rmtree
@contextmanager
def temporary_dir(*args, **kwds):
name = mkdtemp(*args, **kwds)
try:
yield name
finally:
shutil.rmtree(name)
with temporary_dir() as dirname:
# do whatever you want
Ответ 2
Я бы предложил две интересные лекции:
1. Оператор with
используется для переноса выполнения блока методами, определенными менеджером контекста. Это позволяет инкапсулировать обычные try...except...finally
шаблонов использования для удобного повторного использования.
2. Вы можете сделать что-то вроде:
with open("foo.txt") as foo_file:
data = foo_file.read()
ИЛИ ЖЕ
from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
do_something()
ИЛИ (Python 3.1)
with open('data') as input_file, open('result', 'w') as output_file:
for line in input_file:
output_file.write(parse(line))
ИЛИ ЖЕ
lock = threading.Lock()
with lock:
# Critical section of code
3. Я не вижу здесь никакого Антипаттерна.
Цитируем погружение в Python:
попробуй.. в конце концов это хорошо. с лучше.
4. Я думаю, это связано с привычкой программистов использовать оператор try..catch..finally
из других языков.
Ответ 3
Оператор Python with
представляет собой встроенную поддержку языка Resource Acquisition Is Initialization
идиомы, обычно используемой в С++. Он предназначен для безопасного сбора и освобождения ресурсов операционной системы.
Оператор with
создает ресурсы в пределах области/блока. Вы пишете свой код, используя ресурсы внутри блока. Когда блок выходит из ресурсов, они очищаются бесплатно независимо от результата кода в блоке (то есть, выходит ли блок из обычного или из-за исключения).
Многие ресурсы в библиотеке Python, которые подчиняются протоколу, требуемому оператором with
, и поэтому могут использоваться с ним из коробки. Однако каждый может создавать ресурсы, которые могут использоваться в инструкции с помощью хорошо документированного протокола: PEP 0343
Используйте его всякий раз, когда вы приобретаете ресурсы в своем приложении, которые должны быть явно отказаны, например файлы, сетевые подключения, блокировки и т.д.
Ответ 4
Примером антипаттерна может быть использование with
внутри цикла, когда было бы более эффективно иметь with
вне цикла
например
for row in lines:
with open("outfile","a") as f:
f.write(row)
против
with open("outfile","a") as f:
for row in lines:
f.write(row)
Первый способ - открытие и закрытие файла для каждого row
, что может вызвать проблемы с производительностью по сравнению со вторым способом при открытии и закрытии файла только один раз.
Ответ 5
Снова для полноты я добавлю свой самый полезный прецедент для операторов with
.
Я занимаюсь многими научными вычислениями, и для некоторых видов деятельности мне нужна библиотека Decimal
для произвольных вычислений точности. Некоторая часть моего кода мне нужна высокая точность, и для большинства других частей мне нужна меньшая точность.
Я установил свою точность по умолчанию на низкое число, а затем использовал with
, чтобы получить более точный ответ для некоторых разделов:
from decimal import localcontext
with localcontext() as ctx:
ctx.prec = 42 # Perform a high precision calculation
s = calculate_something()
s = +s # Round the final result back to the default precision
Я использую это много с Гипергеометрическим тестом, который требует деления больших чисел, образующих факториалы. Когда вы выполняете вычисления в геномном масштабе, вы должны быть осторожны с ошибками округления и переполнения.
Ответ 6
См. PEP 343 - инструкция 'with', в конце есть примерный раздел.
... новый оператор "с" на Python язык, чтобы сделать можно отбросить стандартные применения утверждений try/finally.
Ответ 7
точки 1, 2 и 3 достаточно хорошо покрыты:
4: он относительно новый, доступный только в python2.6 + (или python2.5 с использованием from __future__ import with_statement
)
Ответ 8
Оператор with работает с так называемыми менеджерами контекста:
http://docs.python.org/release/2.5.2/lib/typecontextmanager.html
Идея состоит в том, чтобы упростить обработку исключений, выполнив необходимую очистку после выхода из блока "с". Некоторые из встроенных модулей python уже работают в качестве менеджеров контекстов.
Ответ 9
Еще один пример поддержки "из коробки" и тот, который может быть немного озадачен сначала, когда вы привыкли к тому, как ведет себя встроенный open()
, - это connection
объекты популярных модулей базы данных, такие как как:
Объекты connection
являются контекстными менеджерами и как таковые могут быть использованы из коробки в with-statement
, однако при использовании вышеуказанного примечания:
Когда заканчивается with-block
, либо с исключением, либо без, соединение не закрывается. Если with-block
заканчивается с исключением, транзакция откатывается, в противном случае транзакция совершается.
Это означает, что программист должен позаботиться о том, чтобы закрыть соединение самостоятельно, но позволяет получить соединение и использовать его в нескольких with-statements
, как показано в psycopg2 docs:
conn = psycopg2.connect(DSN)
with conn:
with conn.cursor() as curs:
curs.execute(SQL1)
with conn:
with conn.cursor() as curs:
curs.execute(SQL2)
conn.close()
В приведенном выше примере вы заметите, что объекты cursor
psycopg2
также являются менеджерами контекста. Из соответствующей документации о поведении:
Когда a cursor
выходит из with-block
, он закрывается, освобождая любой ресурс, в конечном счете связанный с ним. Состояние транзакции не влияет.
Ответ 10
В python обычно оператор с "используется для открытия файла, обработки данных, присутствующих в файле, а также для закрытия файла без вызова метода close()." with" упрощает обработку исключений, предоставляя операции очистки.
Общая форма с:
with open("file name", "mode") as file-var:
processing statements
Примечание: не нужно закрывать файл, вызывая close() на файле-var.close()
Ответ 11
Все возможные решения перечислены в приведенных выше ответах.
Я использую исчерпывающие ключевые слова для читсов:
Keywords_33=[('File_2', ['with', 'as']),
('Module_2', ['from', 'import']),
('Constant_3', {'bool': ['False', 'True'],
'none': ['None']}),
('Operator_4', {'boolean_operation': {'or', 'and', 'not'},
'comparison': {'is'}}),
('Sequnce_operation_2', ['in', 'del']),
('Klass_1', ['class']),
('Function_7',['lambda', 'def', 'pass',
'global', 'nonlocal',
'return', 'yield']),
('Repetition_4', ['while', 'for', 'continue', 'break']),
('Condition_3', ['if', 'elif', 'else']),
('Debug_2', ['assert', 'raise']),
('Exception_3', ['try', 'except', 'finally'])]