gpt4 book ai didi

python - 在抽象方法上实现 "after"装饰器

转载 作者:行者123 更新时间:2023-12-02 02:53:03 24 4
gpt4 key购买 nike

我正在尝试编写一个抽象基类 A,它将具有一个抽象方法 run,用户/开发人员将重载该方法。我想强制执行一些“之后”行为自动应用于派生类 B,以便在 B.run() 运行之后,它当然是另一种标准方法将被调用(在数据管道中,这可能例如提交或回滚事务)。有办法实现吗?

我失败的幼稚尝试是:

def do_the_other_thing(func): 
def wrapper():
func()
print('doing the other thing!')
return wrapper

class A:
@do_the_other_thing
def run(self):
pass

class B(A):
def run(self):
print('running!')

B().run()
>>> 'running!'
>>> #'doing the other thing!' # <--- is there a way to get this?

我当然可以通过创建一个从非抽象方法 A.run 调用的不同抽象方法(例如 _run)来实现解决方法,但这是不太优雅。

我可以在 2007 年看到这种情况 PEP 3124确切指定了此功能,但我找不到任何现代引用资料。

最佳答案

如果您不希望用户自己装饰运行,您实际上不能单独使用函数装饰器做您想做的事。您可以使用类装饰器,__init_subclass__ , 或 metaclasses .


使用类装饰器,

class A:
def run(self):
pass

def do_the_other_thing(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
print('doing the other thing!')
return wrapper


def pipeline_thing(cls):
cls.run = do_the_other_thing(cls.run)
# do some other work
return cls


@pipeline_thing
class B(A):

def run(self):
print("running!")

或者用__init_subclass__

class A:
def run(self):
pass

def __init_subclass__(cls):
super().__init_subclass__()
cls.run = do_the_other_thing(cls.run)
# do some other work

class B(A):

def run(self):
print("running!")

或者使用元类

class AMeta(type):

def __init__(cls, name, bases, attrs, **kwargs):
super().__init__(name, bases, attrs)
cls.run = do_the_other_thing(cls.run)
# do some other work

class A(metaclass=AMeta):
def run(self):
pass

class B(A):

def run(self):
print("running!")

这个例子对元类来说太过分了(你正在使用 metaclass.__init__ - 元类中最不强大的魔法方法,你的行为可以用 __init_subclass__ 完成(这是the intended use of __init_subclass__ )。以这种方式使用元类将阻止您的用户使用元类,并且会使您的代码不必要地复杂化。如果您需要管道来做更多的事情,您可以使用它们(比如您是否需要访问 __new__).

我会使用 __init_subclass__ 或类装饰器(@pipe 或其他东西),它也可能将 BA。作为,alkasm提到,你可以让A继承自abc.ABC,并用abc.abstractmethod修饰run来确保子类实现

关于python - 在抽象方法上实现 "after"装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61615935/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com