是否可以使用 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__
.
等魔术方法一起使用
出于好奇,我很感兴趣是否可以编写一个元 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__
.