I want to get all class variable names of all sub-classes in my parent class (in python). While I managed to do that I'm not certain if there is a cleaner way to achieve that.
Pseudo code to explain the problem :
class Parent:
all_names = []
var_1 = 1
def __init__(self):
print(self.all_names)
class ChildA(Parent):
var_2 = 2
class ChildB(ChildA):
var_3 = 3
p = Parent()
ca = ChildA()
cb = ChildB()
>>> ["var_1"]
>>> ["var_1","var_2"]
>>> ["var_1","var_2","var_3"]
So what I am currently doing is that I use the __new__
function to set those values recursively :
class Parent(object):
test_1 = 1
signals = []
def __new__(cls, *args, **kwargs):
# create obj ref
_obj = super().__new__(cls, *args, **kwargs)
signals = []
# walk every base and add values
def __walk(base):
for key, value in vars(base).items():
if <condition>
signals.append(value.__name__)
for base in base.__bases__:
__walk(base)
__walk(cls)
signals.reverse() # to reorder the list
_obj.signals = signals
return _obj
For more context: I am trying to develop a Signal-System but to check whether an instance has a Signal I somehow need to add them to the Root-Parent-Class. Yes I could Make all Subclasses inherit from a helper class but I don't want to do that and instead have it all bundled in as few classes as possible.
Also if there are any bugs/risks with my implementation please let me know I just recently discovered __new__
.
(Python 3.x)
CodePudding user response:
You could walk up the method resolution order and check for any keys in each class's __dict__
that do not appear in object.__dict__
and are not callable or private keys.
class Parent:
var_p = 1
def __init__(self):
self.blah = 0
class_vars = []
for cls in self.__class__.mro()[:-1]:
class_vars.extend([
k for k, v in cls.__dict__.items()
if k not in object.__dict__ and not k.startswith('_')
and not callable(v)
])
print(class_vars)
def test(self):
return True
class ChildA(Parent):
var_a = 2
class ChildB(ChildA):
var_b = 3
p = Parent()
ca = ChildA()
cb = ChildB()
# prints:
['var_p']
['var_a', 'var_p']
['var_b', 'var_a', 'var_p']