Я озадачен тем, как расположить все, что могут делать менеджеры контекста Python, в соответствующих местах.
Насколько я понимаю, элементы, которые потенциально могут быть использованы при создании диспетчера контекста, включают:
- A: то, что всегда случается
- B: Некоторая подготовка необходима для C
- C: создать и установить объект X, используемый в контексте
- D: Делайте то, что происходит, используя успешно установленный X до начала контекста.
- E: вернуть X в контекст (для использования
as
) - F: Завершите знаком X, когда все в порядке, в конце контекста.
- G: проанализируйте последствия неудачи в C и B, прежде чем входить в контекст
- H: разбирайтесь с последствиями неудач в контексте
Я думаю, что примерно понимаю, где каждый из этих элементов находится в функции диспетчера контекста, но совершенно не понимаю, как расположить их по классам.
Есть ли шаблон для функций и классов диспетчера контекста, который показывает, входит ли каждый из этих элементов в функции и (особенно) классы? Я просмотрел много примеров здесь и в других местах, но не нашел ни одного исчерпывающего, и многие из них используют реальный код, который я не всегда могу сопоставить с каждым из указанных выше строительных блоков.
Я думаю, что в основном понимаю, как ведет себя диспетчер контекста, реализованный через функцию:
from contextlib import contextmanager
@contextmanager
def log_file_open(oec_data, build_description, log_dir):
# A: Something that always happens
try:
# B: Some stuff needed to make a_thing
a_thing = establish_thing_in_a_way_that_might_fail() # C
# D: Some things that happen using a_thing at context start
yield a_thing # E
# F: Wrap up with a_thing when all is well
except:
# G: Deal the consequences of failure in try or...
# H: Deal the consequences of failure in context
finally:
# Could F go here instead?
Например, чтобы открыть файл, в который следует что-то записать при успешном открытии и закрытии, но который следует очистить, если есть проблема, я мог бы написать
from contextlib import contextmanager
@contextmanager
def log_file_open(oec_data, build_description, log_dir):
print('Entering context...')
try:
usable_file_name = get_some_name()
a_thing = open(usable_file_name, mode='w')
a_thing.write('Logging context started.')
yield a_thing
a_thing.write('Logging context ended.')
except:
a_thing.close()
os.remove(a_thing.name)
raise
Но я не уверен, что это правильно, и я не понимаю, как это соотносится с использованием __enter()__
и __exit()__
в классах. Это (схематично):
def __init__(self):
# A: Something that always happens
def __enter__(self):
try:
# B: Some stuff needed to make a_thing
a_thing = establish_thing_in_a_way_that_might_fail() # C
# D: Some things that happen using a_thing at context start
except:
# G: Deal the consequences of failure in try
a_thing = some_appropriate_blank_value
finally:
return a_thing # E
def __exit__(self, type, value, traceback):
if type is None:
# F: Wrap up with a_thing when all is well
return True
else:
# H: Deal the consequences of failure in context
return False