Итак, я пишу интерфейсную среду, которая позволяет людям писать набор команд.
То, что я пытаюсь сделать здесь, это то, что для каждого подкласса Base
найдите все его методы, которые имеют описание, затем соберите все эти функции и сгенерируйте из них общее описание (плюс кое-чтоиначе, но это не имеет отношения к этому вопросу)
Вот 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)
Теперь проблема с моим текущим методом состоит в том, что он не обнаруживает переопределения метода.Предположим, я добавляю этот фрагмент в определение класса B
def a(self): pass
a.description='B.a'
Теперь сгенерированные описания будут полностью неверными.Я хочу, чтобы, когда метод был переопределен, его собранное описание также было переопределено.Поэтому описание всегда должно указывать на метод, к которому Python обычно обращался бы, если бы люди делали это обычными способами (например, B.a.description
)
Таким образом, ожидаемый результат изменится на
a: B.a
b: A.b
c: B.c
d: B.d
Полагаю, я могу сделать специальный случай из слова descriptions
и исправить первый description
метод.
Но есть ли более элегантный и Pythonic способ достичь этого?Если честно, self.__class__.__mro__
выглядит довольно ужасно.