dan*_*jar 5 python inheritance metaprogramming metaclass python-3.x
出于好奇,我想知道是否可以编写一个元类,使父类的方法优先于子类的方法。我想玩一会儿。不可能再覆盖方法了。基类必须显式调用子方法,例如使用对基实例的引用。
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)
Run Code Online (Sandbox Code Playgroud)
随着输出:
验证参数
计算
验证结果
如果您只关心以相反的顺序查找实例(而不是类),那么您甚至不需要元类。你可以覆盖__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
Run Code Online (Sandbox Code Playgroud)
这种机制相对简单,因为类的查找不是反向的:
>>> Child.apply
<function Child.apply at 0x0000000002E06048>
Run Code Online (Sandbox Code Playgroud)
这使得只需在类而不是实例上进行“正常”查找就变得很容易。但是,在其他情况下,这可能会导致混乱,例如基类方法尝试访问子类上的不同方法,但该方法实际上不存在于该子类上;在这种情况下,查找将按正常方向进行,并可能找到更高类上的方法。换句话说,执行此操作时,您必须确保不会在类上查找任何方法,除非您确定它们是在该特定类上定义的。
很可能在其他极端情况下这种方法不起作用。特别是你可以看到我临时操纵了描述符处理;__set__
如果它对带有 a 的描述符做了一些奇怪的事情,或者对于更频繁地使用传递给 的类/对象参数的更复杂的描述符,我不会感到惊讶__get__
。此外,此实现会依赖于以两个下划线开头的任何属性的默认行为;__init__
改变这一点需要仔细考虑它将如何与像和一样的魔术方法一起工作__repr__
。
归档时间: |
|
查看次数: |
1513 次 |
最近记录: |