首页 > 解决方案 > 在上下文管理器开始之前停止并终止它(但在它的 __init__ 之后)

问题描述

我有一个上下文管理器,它是父类/上下文管理器的子类,如果在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')

标签: pythonwith-statementcontextmanager

解决方案


一个相当明显的解决方法是引发异常。

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)

推荐阅读