如何(在 Python 3 中)获取属于特定类的所有属性的值。我只需要那些在特定类中定义的值(属性),而不需要继承的值。
这是一些例子:
class A(object):
def __init__(self, color):
self._color = color
@property
def color(self):
return self._color
class B(A):
def __init__(self, color, height, width):
super().__init__(color)
self._height = height
self._width = width
@property
def height(self):
return self._height
@property
def width(self):
return self._width
这是获取所有值(包括继承的值)的代码:
b_inst = B('red', 10, 20)
val = [{p: b_inst.__getattribute__(p)} for p in dir(B)
if isinstance(getattr(B, p), property)]
print(val)
>> [{'color': 'red'}, {'height': 10}, {'width': 20}]
现在,我只想检索仅在
class B
中定义的属性值,即 height
和 width
。
请注意,在 Python 中,“属性”具有非常具体的含义(内置
property
类型)。如果您只关心这一点,那么您只需查找您孩子班级的__dict__
:
val = [p.__get__(c) for k, p in type(c).__dict__.items() if isinstance(p, property)]
如果你想要对任何任意属性起作用的东西,那么你所要求的就是不可能的,因为Python对象(有一些例外)是基于字典的(与C ++或Java中基于结构的)和动态的(任何片段)代码可以在每个实例的基础上添加/删除任意属性),因此没有固定模式,也没有给定对象可能拥有或不拥有哪些属性的类级定义。
因为,我被这个问题所吸引只是为了找到一个无用的答案,所以我找到了一个:
from collections import defaultdict, deque
from typing import List, Dict
class A:
def __init__(self):
self.value_a1 = 1
self.value_a2 = 2
class B(A):
def __init__(self):
super().__init__()
self.value_b1 = 3
self.value_b2 = 4
class C(A):
def __init__(self):
super().__init__()
self.value_c1 = 5
self.value_c2 = 6
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
self.value_d1 = 7
self.value_d2 = 8
class E(D):
def __init__(self):
super().__init__()
self.value_e1 = 9
self.value_e2 = 10
def build_inheritance_graph(classes) -> Dict[object, List[object]]:
"""
:param classes:
:return:
"""
inheritance_graph = {}
# Recursive function to populate the graph for a class and its ancestors
def add_class_and_ancestors(cls):
if cls not in inheritance_graph:
inheritance_graph[cls] = list(cls.__bases__)
for parent in cls.__bases__:
add_class_and_ancestors(parent)
for cls in classes:
add_class_and_ancestors(cls)
return inheritance_graph
def topological_sort(inheritance_graph) -> List[object]:
"""
:param inheritance_graph:
:return:
"""
# Calculate in-degrees for each class
in_degree = defaultdict(int)
for cls, parents in inheritance_graph.items():
in_degree[cls] += 0 # Ensure each class is initialized in in_degree
for parent in parents:
in_degree[parent] += 0
in_degree[cls] += 1
# Collect classes with no incoming edges (in-degree of 0)
queue = deque([cls for cls, degree in in_degree.items() if degree == 0])
sorted_classes = []
while queue:
cls = queue.popleft()
sorted_classes.append(cls)
for child, parents in inheritance_graph.items():
if cls in parents: # Check if cls is a parent of child
in_degree[child] -= 1
if in_degree[child] == 0:
queue.append(child)
return sorted_classes
def get_declared_attributes(cls):
"""Return instance attributes defined directly in the given class's __init__."""
# Create a temporary instance
instance = cls()
# Capture all instance attributes
all_attrs = set(vars(instance).keys()) if hasattr(instance, '__dict__') else set()
# Check parent classes to remove inherited attributes
for base in cls.__bases__:
parent_instance = base()
parent_attrs = set(vars(parent_instance).keys()) if hasattr(parent_instance, '__dict__') else set()
all_attrs -= parent_attrs
return all_attrs
def get_mapping(classes):
"""
:param classes: list of class types
:return:
"""
graph = build_inheritance_graph(classes)
# Get classes sorted from least to most dependency
sorted_classes_ = topological_sort(graph)
props_by_class = list()
# Display the sorted classes
print("Classes sorted by dependency (from least to most):")
for cls_ in sorted_classes_:
props_list = get_declared_attributes(cls_)
parents_list = [p.__name__ for p in graph[cls_]]
# print(cls_.__name__, "->", parents_list, ": ", props_list)
props_by_class.append({
"class": cls_,
"parents": parents_list,
"properties": list(props_list)
})
return props_by_class
# Build the inheritance graph
mapping = get_mapping(classes=[B, C, D, E])
for item in mapping:
print("class:", item['class'].__name__, "\n\tparents:", item['parents'], "\n\tproperties:", item['properties'])