首页 > 解决方案 > 类内引用的上下文管理

问题描述

__del__在清理 Python 类时,这似乎是一个糟糕的选择,主要是因为并不总是保证会调用它。假设我有一个流程管理类,如下所示:

class ProcessCTL(object):
    def __init__(self):
        self._procs = {}

    def __getitem__(self, key):
        return self._procs[key]

    def __setitem__(self, key, cls):
        self._procs[key] = cls

    def __iter__(self):
        return iter(self._procs.items())

    def __del__(self):
        self.kill_all()

    def start_all(self):
        for _, cls in self:
            cls.start()

    def kill_all(self):
        for _, cls in self:
            cls.kill()

start它只是保留了对另一个实现子进程的 Python 类的引用字典kill

然后ProcessCTL可以在其他类中使用该类,如下所示:

class Foo(object):
    def __init__(self):
        self.pctl = ProcessCTL()
        self.pctl['db'] = DBConnection()
        self.pctl.start_all()

    def do_work(self, stmt):
        self.pctl['db'].execute(stmt)
        return self.pctl['db'].fetchall()

但是,当Foo被删除时,不能保证DBConnection.kill会被调用。我可以添加另一个类似Foo.close的方法轮流调用ProcessCTL.kill_all,但我不想依赖开发人员调用close,并且想自动处理事情。

其他选项包括类似的东西atexit,但这里的问题再次是开发人员可能会选择以Foo某种奇怪的方式使用,或者发送未被处理的信号atexit等。

对其他对象的引用进行“类级别”上下文管理的最佳方法是什么,以便Foo可以创建一个实例,并且一旦使用它,我保证ProcessCTL.kill_all也会被调用?

我试过添加__enter____exit__方法ProcessCTL,希望这样的事情是可能的:

class ProcessCTL(object):
    def __init__(self):
        self._procs = {}

    def __getitem__(self, key):
        return self._procs[key]

    def __setitem__(self, key, cls):
        self._procs[key] = cls

    def __iter__(self):
        return iter(self._procs.items())

    def __del__(self):
        self.kill_all()

    def __enter__(self):
        return self

    def __exit__(self, t, v, e):
        self.kill_all()

    def start_all(self):
        for _, cls in self:
            cls.start()

    def kill_all(self):
        for _, cls in self:
            cls.kill()

class Foo(object):
    def __init__(self):
        self.pctl = _get_pctl()

    def _get_pctl():
        with ProcessCTL() as pctl:
            pctl['db'] = DBConnection()
            pctl.start_all()
            yield pctl

yield将始终返回 a generator,而不是对已创建ProcessCTL实例的引用。

标签: python-3.xyieldcontextmanageratexit

解决方案


推荐阅读