Python 实施";“之后”;一种抽象方法上的装饰器

Python 实施";“之后”;一种抽象方法上的装饰器,python,overloading,Python,Overloading,我正在尝试编写一个抽象基类A,它将有一个抽象方法运行,用户/开发人员可能会过载。我希望强制将一些“after”行为自动应用于派生类B,以便在B.run()运行它的过程后,将调用另一个标准方法(在数据管道中,这可能是提交或回滚事务)。有没有办法做到这一点 我在这方面失败的天真尝试是: def做其他事情(func): def包装器(): func() 打印('做其他事情!') 返回包装器 A类: @做另一件事 def运行(自): 通过 B(A)类: def运行(自): 打印('正在运行!') B()

我正在尝试编写一个抽象基类
A
,它将有一个抽象方法
运行
,用户/开发人员可能会过载。我希望强制将一些“after”行为自动应用于派生类
B
,以便在
B.run()
运行它的过程后,将调用另一个标准方法(在数据管道中,这可能是提交或回滚事务)。有没有办法做到这一点

我在这方面失败的天真尝试是:

def做其他事情(func):
def包装器():
func()
打印('做其他事情!')
返回包装器
A类:
@做另一件事
def运行(自):
通过
B(A)类:
def运行(自):
打印('正在运行!')
B().run()
>>>“跑!”

>>>#“做另一件事!”# 如果您不希望用户自己装饰
运行
,那么您实际上无法单独使用函数装饰器来完成所需的工作。您可以使用类装饰器,或者


有一个班级装饰师

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!")
或者使用
\uuuu init\u子类

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!")

这个例子对于元类来说是杀伤力太大了(您使用的是
元类.\uuuuu init\uuuu
——元类中最不强大的魔法方法,您的行为可以通过
\uuuuuu init\u子类\uuuuuu
来完成(这是)。以这种方式使用元类将阻止您的用户使用元类,这将不必要地使您的代码复杂化。如果您需要管道来发挥更大的作用,您可以使用它们(例如,如果您需要访问
\uuuuu new\uuu


我会使用
\uuuu init\u子类\uuuu
或类装饰器(
@pipe
或其他东西)正如前面提到的,您可以让
A
继承
abc.abc
并用
abc.abstractmethod
修饰
run
,以确保子类实现它。

不要重写
run
;重写
run
调用的方法

然后


Decorators将在定义函数时替换函数,因此我认为没有任何干净的方法可以在不做“标记”的情况下知道函数已被修饰(以便可以将其应用于子类)以某种方式;例如,向函数或类添加属性以供以后阅读。您可以使用
\uu init\u subclass\uu
循环遍历在子类上定义的所有方法,然后将装饰器应用于带有标记的方法。我想您还必须保存要使用的装饰器,也许标记可以是装饰器本身。元类更简单的是,您可以让元类通过类定义的方法运行,并包装满足某些条件的方法(例如,命名为
run
)每个子类也会出现这种情况。请参阅,例如,和使用元类也允许您使用
abc。abstractmethod
强制用户在实例化类时重写正确的方法(否则仅在调用方法时出错),请看。我同意-但我认为OP希望避免这种情况,正如他们在问题中所说。这是一种简单的方法(这总是好的).我同意,我认为
\uuuuu init\uuuuu subclass\uuuuuu
是解决这一问题的方法,因为它最有意义,也是处理抽象类初始化/父类更改的任何子类的最干净的方法
class A:
    def run(self):
        self.do_run()
        print('doing the other thing!')

    def do_run(self):
        pass


class B(A):
    def do_run(self):
        print('running!') 
>>> B().run() 
running!
doing the other thing!