我怎么知道哪个基 class 将特定属性添加到子 class 对象

How can I know which base class adds a specific attribute to a child class object

我正在处理一个项目,该项目具有来自不同文件中多个模块的 classes 的长层次结构。

我想知道在继承链中什么时候class C得到了属性A (然后我可以获得定义 C 的模块 M 并检查代码)

考虑下面的代码示例,假设除了 GrandChildOf1ChildOf2 之外的所有 classes 都在其他模块中,是否有命令,例如:attribute_base(o4,'a') 输出: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__())

输出:

['a']
['b']
['a', 'c']
['a', 'b', 'c', 'd']

我认为没有内置函数,但类似的东西会起作用(它需要改进):

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

这将 return 您 class 的第一个碱基 class 得到您正在寻找的属性。它显然并不完美。如果你的两个或多个基础 classes 具有相同的属性(具有相同的名称),它可能不是 return 你获得属性的实际 class,但在你的例子中它会工作。 [更新 AKX 评论:使用 __mro__ 实际上应该可以解决这个问题]

[更新:有一种方法可以在没有实例的情况下做到这一点,遵循这个有据可查的答案:]

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 为您提供 class 的每个成员,包括我们想要的 init 方法。我们需要检查它是否真的是一个函数 (hasattr(member[1], "__code__")) 因为如果没有为 class 定义 __init__ 函数(就像你的例子中的 SweetDir),这将 return 一个 wrapper_descriptor。我们在罕见(可能?)的情况下循环成员有几种 __init__ 方法。