是否可以使用 Python 元 class 反转继承?

Is it possible to inverse inheritance using a Python meta class?

出于好奇,我很感兴趣是否可以编写一个元 class 来使父 classes 的方法优先于子 classes 的方法。我想玩一会儿。不再可能重写方法。 base class 必须显式调用 sub 方法,例如使用对 base 实例的引用。

class Base(metaclass=InvertedInheritance):

    def apply(self, param):
        print('Validate parameter')
        result = self.subclass.apply(param)
        print('Validate result')
        return result


class Child(Base):

    def apply(self, param):
        print('Compute')
        result = 42 * param
        return result


child = Child()
child.apply(2)

输出:

Validate parameter
Compute
Validate result

如果您只关心按相反顺序查找 实例 (不是 classes),您甚至不需要元 class.您可以覆盖 __getattribute__:

class ReverseLookup:
    def __getattribute__(self, attr):
        if attr.startswith('__'):
            return super().__getattribute__(attr)
        cls = self.__class__
        if attr in self.__dict__:
            return self.__dict__[attr]
        # Using [-3::-1] skips topmost two base classes, which will be ReverseLookup and object
        for base in cls.__mro__[-3::-1]:
            if attr in base.__dict__:
                value = base.__dict__[attr]
                # handle descriptors
                if hasattr(value, '__get__'):
                    return value.__get__(self, cls)
                else:
                    return value
        raise AttributeError("Attribute {} not found".format(attr))

class Base(ReverseLookup):
    def apply(self, param):
        print('Validate parameter')
        result = self.__class__.apply(self, param)
        print('Validate result')
        return result

class Child(Base):
    def apply(self, param):
        print('Compute')
        result = 42 * param
        return result

>>> Child().apply(2)
Validate parameter
Compute
Validate result
84

这种机制相对简单,因为 class 上的查找不是反向的:

>>> Child.apply
<function Child.apply at 0x0000000002E06048>

这使得只需在 class 而不是实例上进行查找即可轻松获得 "normal" 查找。但是,在其他情况下,这可能会导致混淆,例如,如果基 class 方法试图访问 subclass 上的不同方法,但该 subclass 上实际上不存在该方法=];在这种情况下,查找将按正常方向进行,并可能在更高的 class 上找到该方法。换句话说,在执行此操作时,您必须确保不会在 class 上查找任何方法,除非您确定它们是在特定的 class.

上定义的

很可能还有其他极端情况这种方法不起作用。特别是你可以看到我临时操纵了描述符处理;如果它对带有 __set__ 的描述符或更复杂的描述符更频繁地使用传递给 __get__ 的 class/object 参数做了一些奇怪的事情,我不会感到惊讶。此外,此实现依赖于任何以两个下划线开头的属性的默认行为;更改此设置需要仔细考虑它如何与 __init____repr__.

等魔术方法一起使用