Озадачен съм как да подредя всички неща, които контекстните мениджъри на Python могат да правят, на подходящите места.
Доколкото разбирам, елементите, които потенциално могат да влязат в изграждането на контекстен мениджър, включват:
- О: Нещо, което винаги се случва
- 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