Parent
class is inherited by multiple other classes.
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
and V_2
are different in each child (also they don't change once the class is created).
Using the code below I get the same value for ALL_V_ELEMENTS
:
print(Parent.ALL_V_ELEMENTS) # prints: set()
print(Child1.ALL_V_ELEMENTS) # prints: set()
print(Child2.ALL_V_ELEMENTS) # prints: set()
Which is something I don't want. What I need is this:
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'}
To achieve my goal I can define the classes as follows:
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
However, copy-pasting ALL_V_ELEMENTS = V_1 | V_2
on every child of Parent
doesn't seem like a good idea.
Another alternative would be defining Parent
in a different way:
class Parent(object):
V_1 = set()
V_2 = set()
def __init__(self):
self.ALL_V_ELEMENTS = self.V_1 | self.V_2
This would do the |
operation on every instance which is redundant.
Is there a better way to achieve my goal?
You could define it as a property:
class Parent(object):
V_1 = set()
V_2 = set()
@property
def ALL_V_ELEMENTS(self):
return V_1 | V_2
This would, however, re-calculate the set each time. Having the __init__
create the set means it'll be created for every instance.
You could calculate the set in a metaclass, so it is only produced when the class object is produced:
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
This metaclass adds a ALL_V_ELEMENTS
union to any subclass; use it like this:
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'}
Demo:
>>> 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'}