#python #with-statement #contextmanager
#python #с помощью-statement #contextmanager
Вопрос:
У меня есть контекстный менеджер, подкласс родительского класса / context-manager, который я хотел бы завершить как можно скорее, если какое-то условие выполняется во время super().__init__
.
class CM:
def __init__(self, *args, **kwargs):
print('__init__')
super().__init__(*args, **kwargs)
self.condition_depending_on_super_init_result = True # set to true just to showcase the question
if self.condition_depending_on_super_init_result:
self.__exit__() # this has no impact: the lines after "with cm:" below are still executed!
self = None # why?
def __enter__(self):
print('__enter__')
def __exit__(self, *args):
print('__exit__')
def dosomething(self, x):
print(x)
cm = CM()
print('before with')
with cm: # here it should skip the block, not enter it, and not do the next lines
print('after with')
cm.dosomething('dosomething')
Комментарии:
1. Контекстные менеджеры не могут контролировать выполнение
with
тела.
Ответ №1:
Одним из достаточно очевидных обходных путей является создание исключения.
import logging # or whatever
class CMInitException(Exception):
"""
Exception raised by CM.__init__() if the superclass fails to initialize.
"""
pass
class CM:
def __init__(self, *args, **kwargs):
print('__init__')
super().__init__(*args, **kwargs)
self.condition_depending_on_super_init_result = True # set to true just to showcase the question
if self.condition_depending_on_super_init_result:
raise CMInitException("The moon over Redmond is not 3/4 full waxing")
def __enter__(self):
print('__enter__')
def __exit__(self, *args):
print('__exit__')
def dosomething(self, x):
print(x)
try:
cm = CM()
print('before with')
with cm:
print('after with')
cm.dosomething('dosomething')
except CMInitException as e:
logging.warning(e)
Комментарии:
1. Клянусь, я это придумал. У меня нет доступа к исходному коду Microsoft.
2. Ха-ха! Хорошее решение @tripleee! Изначально я хотел избежать дополнительного
try
except
оператора /, видите ли вы решение, которое позволяет «пресечьcm
в зародыше», чтобы оноwith cm:
немедленно возвращалось и не выполняло внутренние строки?3. Если
cm
не инициализирован, вы не можете сделатьwith cm:
4. при вводе
with ...:
__enter__()
выполняется, возможно ли в этот момент сразу пропустить весь блок внутриwith
?5. Аналогичным образом вы можете вызвать исключение в любой другой точке, если есть другая ситуация, когда вы хотите заставить вызывающего отказаться.