我正在从事一个项目,该项目具有来自不同文件中多个模块的长类层次结构。
我想知道在继承链类C中什么时候得到了属性A (然后我可以获得定义 C 的模块 M 并检查代码)
考虑下面的代码示例,假设除了 GrandChildOf1ChildOf2
之外的所有类都在其他模块中,是否有命令,例如: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
这将返回您的类中第一个具有您正在寻找的属性的基类。它显然并不完美。如果您的两个或多个基类具有相同的属性(具有相同的名称),它可能不会返回您获得该属性的实际类,但在您的示例中它会起作用。
[更新 AKX 评论:使用 __mro__
实际上应该可以解决这个问题]
[更新:有一种方法可以在没有实例的情况下做到这一点,遵循这个有据可查的答案: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
为您提供类的每个成员,包括我们想要的 init 方法。我们需要检查它是否真的是一个函数 (hasattr(member[1], "__code__"))
因为如果没有为类定义 __init__
函数(比如 SweetDir你的例子),这将返回一个 wrapper_descriptor。我们在罕见(可能?)的情况下循环成员有多个 __init__
方法。
关于python - 我怎么知道哪个基类将特定属性添加到子类对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53428143/