Я не думаю, что для этого есть встроенные функции, но что-то подобное сработало бы (это требует улучшений):
def attribute_base(your_class, your_attr):
for base_class in your_class.__mro__:
if base_class != your_class:
tmp_inst = base_class()
if hasattr(tmp_inst, your_attr):
return base_class
Это вернет первый базовый класс вашего класса, который получил атрибутты ищешь.Это явно не идеально.Если два или более ваших базовых классов имеют одинаковый атрибут (с одинаковым именем), он может не возвращать фактический класс, в котором вы получили атрибут, но в вашем примере он будет работать.[Обновление с комментарием AKX: использование __mro__
действительно должно решить эту проблему]
[Обновление: есть способ сделать это без экземпляра, следуя этому сильно документированному ответу: list-the-attribute-of-a-class-без объекта-экземпляра-объекта ]
from inspect import getmembers
def attribute_base(your_class, your_attr):
for base_class in your_class.__mro__:
if base_class != your_class:
members = [member[1].__code__.co_names for member in getmembers(base_class) if '__init__' in member and hasattr(member[1], "__code__")]
for member in members:
if your_attr in members:
return base_class
getmembers
дает вам каждый член класса, включая методы init, что нам и нужно.Нам нужно проверить, действительно ли это функция (hasattr(member[1], "__code__"))
, потому что, если для класса не определена функция __init__
(как, например, SweetDir в вашем примере), она вернет wrapper_descriptor.Мы зациклились на членах, в редком (возможном?) Случае есть несколько __init__
методов.