【发布时间】:2020-11-11 07:14:58
【问题描述】:
我有一个类层次结构,其中一些方法使用在类级别定义的属性列表。
假设对于A 类,我有A.X = [propA1, propA2],对于C 子类,我需要C.X = [propA1, propA2, propC]。子类从父类继承属性,因此使用super() 调用编写类方法是有意义的,每个方法都使用自己类的属性。
但是,它有点麻烦。我可以在基类的一个方法中处理所有属性。因此,为每个子类定义一个包含一组新属性的类变量并手动向下 cls.__mro__ 检索所有属性真的感觉更自然。
我想出的(下)似乎相对透明,但它是惯用的吗?是否有更典型的编码模式?有没有办法避免装饰所有子类?
class Base(object):
pass
class InheritClassVariable:
def __init__(self, var, base):
self.var = var
self.base = base
def __call__(self, cls):
name = self.var
uname = '_' + name
bases = [B for B in cls.__mro__ if issubclass(B, self.base)]
setattr(cls, uname, getattr(cls, name, []))
value = [item for B in bases for item in getattr(B, uname, [])]
setattr(cls, name, value)
return cls
@InheritClassVariable('X', Base)
class A(Base):
X = ['propA1', 'propA2']
@InheritClassVariable('X', Base)
class B(Base):
X = ['propB']
@InheritClassVariable('X', Base)
class C(A):
X = ['propC']
@InheritClassVariable('X', Base)
class D(C,B,A):
X = ['propD']
if __name__ == "__main__":
print(f"D.X = {D.X}")
【问题讨论】:
-
我通过使用元类回答了大致相似的问题。 stackoverflow.com/a/62164653/1394353
habits似乎等同于X。元类通常是多余的,但对于处理祖先 class 而不是 instance 层次结构很有用。还是一定要谨慎使用。 -
谢谢,我查了元类是什么,并且可以在简单的情况下做到这一点。然后我看到 init_subclass 可用于避免子类,我确实设法以更简单的方式做到这一点。
-
是的,忘了说。切普纳的回答,如果我记得的话。这是一个新功能,直到大约 6 个月前才听说过。不管你怎么做,都要非常小心类级别的可变属性,比如列表。并不是说你不应该使用它们,但你不能让实例再次变异它们。如果需要,请先执行
self.X = self.X.copy()之类的操作。或self.X = self.X + [var]不是self.X.append(var) -
是的,它们是常量。如果它们是可变的,
get()方法会更有意义。顺便说一句,如果两个具有自己元类的层次结构交叉,元类解决方案就会变得尴尬。
标签: python multiple-inheritance class-variables