摆脱明确的超级

Getting rid of explicit super

我想实现这样的东西

def after(f):
    def inner(*args, **kwargs):
        super().f(*args, **kwargs)
        f(*args, **kwargs)
    return inner


class A:
  def f(self):
    print ('hello')


class B(A):

  @after
  def f(self):
    print ('world')

b = B()
b.f()

那是我想在我的一些 classes 中摆脱显式 super 并将其替换为 @before / @after 装饰器(可能带有参数).

也就是说,在这个例子中,我希望打印hello world

想法是为了增加代码的可读性,因为在一些classes中我经常使用多重继承,所以我经常重写方法,经常不得不使用super().

我想我可以使用 inspect 来确定调用装饰器的 class 实例(尽管如果我有很多 class 个实例则性能不确定)。

有没有办法在不牺牲性能的情况下做到这一点?

您可以让您的装饰器工作,您只需要让它成为一个描述符 class,而不是一个函数。您需要实施 __set_name__ 方法以获取对您已添加到的 class 的引用。使用 class 引用,您可以进行两个参数 super 调用:

import functools

class after:
    def __init__(self, method):
        self.method = method

    def __set_name__(self, owner, name):
        self.owner = owner
        self.name = name                 # using self.method.__name__ might be better?

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return functools.partial(self, instance)

    def __call__(self, instance, *args, **kwargs):
        assert(self.owner is not None and self.name is not None)
        getattr(super(self.owner, instance), self.name)(*args, **kwargs)
        return self.method(instance, *args, **kwargs)

你也可以做一个 before,这几乎是一样的,只是最后两行的顺序相反(还有一些小动作来处理 return 值)。

我注意到这个装饰器比以正常方式调用 super 的用处要小得多,因为您无法与被重写方法编辑的值 return 进行有用的交互,或更改传递给它的参数。没有 beforeafter 修饰方法可以复制这些 classes:

class Foo:
    def foo(self, x, y):
        return x + y

class Bar(Foo):
    def foo(self, x, y, z):
        return super().foo(x//2, y+1) * z