从抽象方法继承包装器

Inherit wrapper from abstract method

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

我正在使用 ABC 作为基础 class。我试着把 @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 方式?

如您所见,装饰器不会更改重写的方法。您可以在每次创建 subclass 时修饰该方法。您甚至可以使用魔术方法 __init_subclass__.

自动执行此操作
class Base(ABC):
    ...

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

但我不推荐这种方法。它可能会破坏 ABC 机制,并且从 Extend 继承的 classes 如果不覆盖该方法,则会被修饰两次。

这里有一个更简单的方法。我们在 Base 上定义了一个具体的 "public" 方法,它调用了一个抽象的 "private" 方法。在子 classes 中,我们必须实现 "private" 方法。

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()

另一个优点是您可以在子 class 中更改 "wrapper" 的行为,这对于装饰器来说很难。