首页 > 解决方案 > 从抽象方法继承包装器

问题描述

我想系统地包装一些基类的重写方法。

我正在使用ABC基类。我试图包装@abstractmethod,将注释放在之前或之后,但它不起作用。据我了解,整个包装的方法被覆盖。

from functools import wraps
from abc import ABC, abstractmethod

def print_before(func):
    @wraps(func)
    def out(*args, **kwargs):
        print('Hello')
        return func(*args, **kwargs)

    return out

class Base(ABC):
    @print_before
    @abstractmethod
    def test(self):
        pass

class Extend(Base):
    def test(self):
        print('World')

以下是我们测试时发生的情况:

Extend().test()

结果:

World

期望:

Hello
World

我想我没有使用正确的方法来获得这种行为。在覆盖方法之前和之后运行一些代码的一种不错的 Pythonic 方式是什么?

标签: pythonpython-3.xabstract-classwrapperabc

解决方案


正如您所注意到的,装饰器不会更改被覆盖的方法。您可以在每次创建子类时装饰该方法。您甚至可以使用魔术方法自动完成__init_subclass__

class Base(ABC):
    ...

    def __init_subclass__(cls):
        cls.test = print_before(cls.test)

但我不推荐这种方法。如果它们不重写方法,它可能会破坏ABC机制和继承的类被装饰两次。Extend

这是一个更简单的方法。我们定义了一个具体的“公共”方法,Base它调用了一个抽象的“私有”方法。在子类中,我们必须实现“私有”方法。

class Base(ABC):
    def test(self):
        # do something before
        result = self._do_work()
        # do something after
        return result

    @abstractmethod
    def _do_work(self):
        pass


class Extend(Base):
    def _do_work(self):
        # your implementation here

# use it like this:
e = Extend()
e.test()

另一个优点是您可以更改子类中“包装器”的行为,这对于装饰器来说是很困难的。


推荐阅读