Sil*_*uck 1 python abstract-class abc wrapper python-3.x
我想系统地包装一些基类的重写方法。
我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')
Run Code Online (Sandbox Code Playgroud)
这是我们测试时发生的情况:
Extend().test()
Run Code Online (Sandbox Code Playgroud)
结果:
World
Run Code Online (Sandbox Code Playgroud)
期望:
Hello
World
Run Code Online (Sandbox Code Playgroud)
我想我没有使用正确的方法来获得这种行为。在重写方法之前和之后运行一些代码的好的 Pythonic 方式是什么?
正如您所注意到的,装饰器不会更改被覆盖的方法。每次创建子类时都可以装饰该方法。您甚至可以使用魔术方法自动执行此操作__init_subclass__。
class Base(ABC):
...
def __init_subclass__(cls):
cls.test = print_before(cls.test)
Run Code Online (Sandbox Code Playgroud)
但我不会推荐这种方法。如果它们不覆盖该方法,它可能会破坏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()
Run Code Online (Sandbox Code Playgroud)
另一个优点是您可以更改子类中“包装器”的行为,这对于装饰器来说是困难的。