【问题标题】:Inherit wrapper from abstract method从抽象方法继承包装器
【发布时间】:2019-09-03 12:00:48
【问题描述】:

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

我使用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

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

【问题讨论】:

    标签: python python-3.x abstract-class wrapper abc


    【解决方案1】:

    如您所见,装饰器不会更改被覆盖的方法。您可以在每次创建子类时装饰该方法。您甚至可以使用魔术方法__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()
    

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

    【讨论】:

    • 谢谢,您的第二个解决方案非常聪明!
    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2013-11-28
    • 2012-01-09
    • 2013-07-01
    • 2012-08-06
    • 2014-07-09
    • 1970-01-01
    相关资源
    最近更新 更多