So I'm writing an interface framework that allow people to write a collection of commands.
What I am trying to do here is that, for each subclass of Base, find all of its methods that has a description, then collect all those functions and generate a collective description out of them (plus something else, but its not relevant to this question)
Here is MCVE
import types
class Meta(type):
def __init__(cls, *args, **kwargs):
cls._interfaces = {}
super().__init__(*args, **kwargs)
def __call__(cls, id, *args, **kwargs):
if id in cls._interfaces:
return cls._interfaces[id]
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
cls._interfaces[id] = obj
return obj
class Base(metaclass=Meta):
@property
def descriptions(self): # this doesn't work. It gives RecursionError
res=''
for name in dir(self):
attr=getattr(self,name)
if isinstance(attr, types.FunctionType) and hasattr(attr, 'description'):
res += f'{name}: {attr.description}\n'
return res
@property
def descriptions(self):
res=''
for cls in self.__class__.__mro__:
for name,attr in cls.__dict__.items():
if isinstance(attr, types.FunctionType) and hasattr(attr, 'description'):
res += f'{name}: {attr.description}\n'
return res
class A(Base):
def a(self): pass
a.description='A.a'
def b(self): pass
b.description='A.b'
class B(A):
def c(self): pass
c.description='B.c'
def d(self): pass
d.description='B.d'
print(B(0).descriptions)
Now the problem with my current method is that it doesn't detect method overrides. Suppose I add this snippet into the definition of class B
def a(self): pass
a.description='B.a'
Now the generated descriptions will be completely wrong. What I want is that when a method got overridden, it's collected description also got overridden. So the description should always point to the method that Python would normally resolve to if people do it with usual ways (e.g. B.a.description)
So the expected output would then change to
a: B.a
b: A.b
c: B.c
d: B.d
I suppose I can make a special case out of word descriptions and fix the first description method.
But is there a more elegant and Pythonic way to achieve that? To be honest, self.__class__.__mro__ looks pretty horrible.
type(self)instead ofself. Without you telling us what you want, it's hard to be sure, though.B.a.description).