Mat*_*und 13 python attributes
假设我们有以下类层次结构:
class ClassA:
@property
def foo(self): return "hello"
class ClassB(ClassA):
@property
def bar(self): return "world"
Run Code Online (Sandbox Code Playgroud)
如果我像这样在ClassB上探索__ dict __,我只看到bar属性:
for name,_ in ClassB.__dict__.items():
if name.startswith("__"):
continue
print(name)
Run Code Online (Sandbox Code Playgroud)
输出是吧
我可以使用自己的方法来获取不仅指定类型而且还包含其祖先的属性.但是,我的问题是,在没有重新发明轮子的情况下,我是否已经在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)
Run Code Online (Sandbox Code Playgroud)
运行我的代码如下......
for attribute_name in return_attributes_including_inherited(ClassB):
print(attribute_name)
Run Code Online (Sandbox Code Playgroud)
...回馈bar和foo.
请注意,我正在简化一些事情:名称冲突,使用items(),对于此示例,我可以使用dict,跳过以__开头的任何内容,忽略两个祖先本身具有共同祖先的可能性等.
EDIT1 - 我试图让这个例子变得简单.但我真的想要每个类和祖先类的属性名称和属性引用.下面的答案之一让我有了一个更好的轨道,当我开始工作时,我会发布一些更好的代码.
EDIT2 - 这就是我想要的,而且非常简洁.它基于以下Eli的答案.
def get_attributes(type):
attributes = set(type.__dict__.items())
for type in type.__mro__:
attributes.update(type.__dict__.items())
return attributes
Run Code Online (Sandbox Code Playgroud)
它返回属性名称及其引用.
EDIT3 - 下面的答案之一建议使用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
Run Code Online (Sandbox Code Playgroud)
ron*_*akg 12
您应该将python的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>)
Run Code Online (Sandbox Code Playgroud)
了解更多关于该inspect模块在这里.