Reputation: 578
i am working on a project with long hierarchy of classes from several modules in different files.
I want to know when in the inheritance chain class C got the attribute A (then I can get the module M where C is defined and inspect the code)
consider the following code example, imagine that all classes except GrandChildOf1ChildOf2
are in other modules, is there a command, something like: attribute_base(o4,'a')
with output: Base1
?
class SweetDir:
def __sweet_dir__(self):
"""
Same as dir, but will omit special attributes
:return: string
"""
full_dir = self.__dir__()
sweet_dir = []
for attribute_name in full_dir:
if not ( attribute_name.startswith('__')
and attribute_name.endswith('__')):
#not a special attribute
sweet_dir.append(attribute_name)
return sweet_dir
class Base1(SweetDir):
def __init__(self):
super(Base1,self).__init__()
self.a = 'a'
class Base2(SweetDir):
def __init__(self):
super(Base2,self).__init__()
self.b = 'b'
class ChildOf1 (Base1):
def __init__(self):
super(ChildOf1,self).__init__()
self.c = 'c'
class GrandChildOf1ChildOf2 (Base2,ChildOf1):
def __init__(self):
super(GrandChildOf1ChildOf2,self).__init__()
self.d = 'd'
o1 = Base1()
o2 = Base2()
o3 = ChildOf1()
o4 = GrandChildOf1ChildOf2()
print(o1.__sweet_dir__())
print(o2.__sweet_dir__())
print(o3.__sweet_dir__())
print(o4.__sweet_dir__())
output:
['a']
['b']
['a', 'c']
['a', 'b', 'c', 'd']
Upvotes: 2
Views: 66
Reputation: 505
I don't think there is a builtin functions for that but something like that would work (It needs improvements) :
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
This will return the first base class of your class that got the attribute you are looking for. It is clearly not perfect. If two or more of your bases classes have the same attribute (with the same name), it might not return the actual class where you got the attribute, but in your exemple it would work.
[Update with AKX comment : using __mro__
should actually solve this problem]
[Update : There is a way to do it without an instance, following this greatly documented answer : list-the-attributes-of-a-class-without-instantiating-an-object ]
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
gives you every member of the class, including the init methods which is what we want. We need to check if it's really a function (hasattr(member[1], "__code__"))
because if no __init__
function is define for a class (like SweetDir in your example), this will return a wrapper_descriptor. We loop on members in the rare (possible?) case there is several __init__
method.
Upvotes: 1