Parent
类由多个其他类继承。
class Parent(object):
V_1 = set()
V_2 = set()
ALL_V_ELEMENTS = V_1 | V_2
class Child1(Parent):
V_1 = {1, }
V_2 = {4, 7, 10}
class Child2(Parent):
V_1 = {'a', 'b'}
V_2 = {'a', 'c'}
V_1
和V_2
在每个子项中都有所不同(创建类后它们也不会更改)。
使用下面的代码我得到ALL_V_ELEMENTS
的相同值:
print(Parent.ALL_V_ELEMENTS) # prints: set()
print(Child1.ALL_V_ELEMENTS) # prints: set()
print(Child2.ALL_V_ELEMENTS) # prints: set()
这是我不想要的。 我需要的是:
print(Parent.ALL_V_ELEMENTS) # prints: set()
print(Child1.ALL_V_ELEMENTS) # prints: {1, 10, 4, 7}
print(Child2.ALL_V_ELEMENTS) # prints: {'a', 'c', 'b'}
为了实现我的目标,我可以按如下方式定义类:
class Child1(Parent):
V_1 = {1, }
V_2 = {4, 7, 10}
ALL_V_ELEMENTS = V_1 | V_2
class Child2(Parent):
V_1 = {'a', 'b'}
V_2 = {'a', 'c'}
ALL_V_ELEMENTS = V_1 | V_2
但是,对ALL_V_ELEMENTS = V_1 | V_2
的每个孩子进行复制粘贴Parent
似乎不是一个好主意。
另一种选择是以不同的方式定义Parent
:
class Parent(object):
V_1 = set()
V_2 = set()
def __init__(self):
self.ALL_V_ELEMENTS = self.V_1 | self.V_2
这将对每个冗余的实例执行|
操作。
有没有更好的方法来实现我的目标?
答案 0 :(得分:1)
您可以将其定义为属性:
class Parent(object):
V_1 = set()
V_2 = set()
@property
def ALL_V_ELEMENTS(self):
return V_1 | V_2
然而,这将每次重新计算该集合。让__init__
创建集合意味着它将为每个实例创建。
您可以在元类中计算集合,因此仅在生成类对象时生成:
class AllVMeta(type):
def __new__(typ, name, bases, attrs):
cls = super(AllVMeta, typ).__new__(typ, name, bases, attrs)
cls.ALL_V_ELEMENTS = cls.V_1 | cls.V_2
return cls
此元类向任何子类添加ALL_V_ELEMENTS
并集;像这样使用它:
class Parent(object, metaclass=AllVMeta):
V_1 = set()
V_2 = set()
class Child1(Parent):
V_1 = {1, }
V_2 = {4, 7, 10}
class Child2(Parent):
V_1 = {'a', 'b'}
V_2 = {'a', 'c'}
演示:
>>> class AllVMeta(type):
... def __new__(typ, name, bases, attrs):
... cls = super(AllVMeta, typ).__new__(typ, name, bases, attrs)
... cls.ALL_V_ELEMENTS = cls.V_1 | cls.V_2
... return cls
...
>>> class Parent(object, metaclass=AllVMeta):
... V_1 = set()
... V_2 = set()
...
>>> class Child1(Parent):
... V_1 = {1, }
... V_2 = {4, 7, 10}
...
>>> class Child2(Parent):
... V_1 = {'a', 'b'}
... V_2 = {'a', 'c'}
...
>>> Child1.ALL_V_ELEMENTS
{1, 10, 4, 7}
>>> Child2.ALL_V_ELEMENTS
{'a', 'c', 'b'}