首页 > 解决方案 > Python 在重写方法中访问父类的“with”语句

问题描述

我有一个基类,其方法使用with语句。在子类中,我重写了相同的方法,然后想访问相同with的语句(而不是有两个with语句)。

解决这个问题的标准方法是什么?

有关示例和可能的解决方案,请参见下文。


样品使用threading.Lock

from threading import Lock


class BaseClass:
    def __init__(self):
        self.lock = Lock()
        self._data = 0

    def do_something_locked(self) -> None:
        with self.lock:
            self._data += 5


class ChildClass(BaseClass):
    def do_something_locked(self) -> None:
        super().do_something_locked()
        # Obviously the parent class's self.lock's __exit__ method has 
        # already been called.  What are accepted methods to add more 
        # functionality inside parent class's "with" statement?
        with self.lock:
            self._data += 1

可能的解决方案

我的第一个倾向是定义一个私有方法,BaseClass如下所示:

    def do_something_locked(self) -> None:
        with self.lock:
            self._do_something()

    def _do_something(self) -> None:
        self._data += 5

然后ChildClass可以只是覆盖_do_something。这将正常工作。

我想知道,还有其他解决这个问题的常见模式吗?

标签: pythonoopwith-statementcontextmanager

解决方案


我的第一个倾向是定义一个BaseClass类似的私有方法......然后ChildClass可以覆盖_do_something。这将正常工作。

这是解决问题的好方法,即使您没有特殊要求(例如需要保留在with块上下文中)。我不会在“钩子”方法名称中使用前导下划线,因为您期望在派生类中被覆盖的任何东西在逻辑上都是类接口的一部分。此外,如果该self._data += 5部分总是需要发生,则将其保留在do_something_locked.

还有其他解决这个问题的常见模式吗?

具体到问题,您可以使用重入锁,如另一个答案所示。您也可以忽略类相关的事实,并使用依赖注入 - 在基类中创建一个通用方法,该方法接受可调用并使用锁执行它:

# in base class
def do_locked(self, what, *args, **kwargs):
    with self.lock:
        what(*args, **kwargs)

# in derived class
def _implementation(self):
    pass
def do_interesting_thing(self):
    # pass in our own bound method, which takes no arguments
    self._do_locked(self._implementation)

这种方式允许客户端代码以自定义方式使用锁。如果您不需要或不想要该功能,这可能不是一个好主意。


推荐阅读