假设我们具有以下类层次结构:
class ClassA: @property def foo(self): return "hello" class ClassB(ClassA): @property def bar(self): return "world"
如果像这样在ClassB上浏览 dict ,我只会看到bar属性:
for name,_ in ClassB.__dict__.items(): if name.startswith("__"): continue print(name)
输出为bar
我可以运用自己的方式来获取属性,不仅是指定类型,还包括其祖先。但是,我的问题是python是否已经有一种方法可以在不重新发明轮子的情况下做到这一点。
def return_attributes_including_inherited(type): results = [] return_attributes_including_inherited_helper(type,results) return results def return_attributes_including_inherited_helper(type,attributes): for name,attribute_as_object in type.__dict__.items(): if name.startswith("__"): continue attributes.append(name) for base_type in type.__bases__: return_attributes_including_inherited_helper(base_type,attributes)
如下运行我的代码…
for attribute_name in return_attributes_including_inherited(ClassB): print(attribute_name)
…同时返回bar和foo。
请注意,我正在简化一些事情:名称冲突,在本例中可以使用dict时使用items(),跳过以__开头的任何内容,忽略两个祖先本身具有一个共同祖先的可能性,等等。
EDIT1-我试图保持示例简单。但是我真的想要每个类和祖先类的属性名称和属性引用。以下答案之一让我步入了更好的轨道,当我开始工作时,我将发布一些更好的代码。
编辑2-这是我想要的,并且非常简洁。它基于以下Eli的答案。
def get_attributes(type): attributes = set(type.__dict__.items()) for type in type.__mro__: attributes.update(type.__dict__.items()) return attributes
它同时返回属性名称及其引用。
编辑3-建议使用inspect.getmembers以下答案之一。这看起来非常有用,因为就像dict一样,它也对祖先类进行操作。
由于我要尝试做的大部分工作是查找标记有特定描述符的属性,并包括祖先类,因此下面的代码可以帮助做到这一点,以防万一:
class MyCustomDescriptor: # This is greatly oversimplified def __init__(self,foo,bar): self._foo = foo self._bar = bar pass def __call__(self,decorated_function): return self def __get__(self,instance,type): if not instance: return self return 10 class ClassA: @property def foo(self): return "hello" @MyCustomDescriptor(foo="a",bar="b") def bar(self): pass @MyCustomDescriptor(foo="c",bar="d") def baz(self): pass class ClassB(ClassA): @property def something_we_dont_care_about(self): return "world" @MyCustomDescriptor(foo="e",bar="f") def blah(self): pass # This will get attributes on the specified type (class) that are of matching_attribute_type. It just returns the attributes themselves, not their names. def get_attributes_of_matching_type(type,matching_attribute_type): return_value = [] for member in inspect.getmembers(type): member_name = member[0] member_instance = member[1] if isinstance(member_instance,matching_attribute_type): return_value.append(member_instance) return return_value # This will return a dictionary of name & instance of attributes on type that are of matching_attribute_type (useful when you're looking for attributes marked with a particular descriptor) def get_attribute_name_and_instance_of_matching_type(type,matching_attribute_type): return_value = {} for member in inspect.getmembers(ClassB): member_name = member[0] member_instance = member[1] if isinstance(member_instance,matching_attribute_type): return_value[member_name] = member_instance return return_value
您应将python的inspect模块用于任何此类自省功能。
inspect
. . >>> class ClassC(ClassB): ... def baz(self): ... return "hiya" ... >>> import inspect >>> for attr in inspect.getmembers(ClassC): ... print attr ... ('__doc__', None) ('__module__', '__main__') ('bar', <property object at 0x10046bf70>) ('baz', <unbound method ClassC.baz>) ('foo', <property object at 0x10046bf18>)
在此处阅读有关inspect模块的更多信息。