python - python:模拟类变量的多重继承
问题描述
我有一个类层次结构,其中一些方法使用在类级别定义的属性列表。
假设对于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}")
解决方案
一位评论员提到了元类,这是我不知道的。我查了一下,发现有一种__init_subclass__
方法可以避免使用元类。
众所周知,我可以将代码简化为(已编辑):
def InheritConstantArray(varname, value=[]):
"""Return a class making the 'varname' array to be inherited in subclasses"""
basename = f"InheritConstantArray{varname}"
def init_subclass(cls):
# it seems __class__ won't work here. I still don't understand
# why. All I know is eval() is dirty so I do a lookup.
allbases = cls.mro()
base = [b for b in allbases if b.__name__ == basename][0]
# collaborate with other classes using __init_subclass__().
# if we want sevaral variables to be inherited.
super(base, cls).__init_subclass__()
# base._X[cls] will store original cls.X
uvarname = f'_{varname}' if varname[0] != '_' else f'{varname}_'
if not hasattr(base, uvarname):
setattr(base, uvarname, {base: value})
stored_values = getattr(base, uvarname)
stored_values[cls] = cls.__dict__.get(varname, [])
# Then we set cls.X value from base classes
bases = [b for b in allbases if issubclass(b, base)]
values = [i for b in bases for i in stored_values.get(b, [])]
print(cls, base)
setattr(cls, varname, values)
dct = {varname: value, '__init_subclass__': init_subclass}
base = type(basename, (object,), dct)
return base
class A(InheritConstantArray('X')):
X = ['A']
class B(A):
X = ['B']
class C(A):
X = ['C']
class D(B,C,InheritConstantArray('Y')):
X = ['D']
Y = ['d']
class E(D):
X = ['E']
Y = ['e']
class F(D):
X = ['F']
Y = ['f']
class G(E,F):
X = ['G']
Y = ['g']
if __name__ == "__main__":
print(f"A.X = {A.X}")
print(f"B.X = {B.X}")
print(f"C.X = {C.X}")
print(f"D.X = {D.X} {D.Y}")
print(f"E.X = {E.X} {E.Y}")
print(f"F.X = {F.X} {F.Y}")
print(f"G.X = {G.X} {G.Y}")
不过,我仍然不确定这是否是标准方法。(是的,在我的实际问题中具有类变量和多重继承是有充分理由的。)
推荐阅读
- c++ - 如何在 C++ 中拥有多个纤程——就像纤程的向量
- azure-iot-hub - Azure IoT 中心所需和报告的属性
- csv - 如何在 awk 脚本中传递命令行参数
- go - 为什么 Go 中的 CLONE_NEWUSER 克隆标志会导致参数无效错误
- android - RecyclerView 中的 EditText 与 Kotlin 不工作
- java - 如何根据来自 2 个不同单选组的 2 个单选按钮选择来更改另一个活动中的 EditText 或 TextView 的文本?
- python - 如何将df中的两列组合为np.where中的条件以检查nan是否在计算新列
- arrays - PowerShell:在 Where-Object 中定义多个条件
- java - 谁能解释这里的美元符号是什么意思?
- git - 如何检查要上传的 lfs 文件?