如何获取类实例字段?编写get_members函数输入类本身获成员
类与实例成员识别及get_members函数实现
一、给定类名,如何发现实例级字段?
实例级字段(比如Mock里的a)是在类实例化时通过self.xxx = ...绑定到实例的,类本身并不存储这些字段,所以直接用vars(clz)、dir(clz)或inspect模块查询类时,无法直接获取到这类字段。要识别它们,有两种实用思路:
- 动态实例化提取:创建类的临时实例(处理
__init__参数时,用占位值如None填充),再通过实例的__dict__或vars()提取字段名。这种方法简单直接,适合大多数场景。 - 解析
__init__源码:用ast模块解析__init__函数的代码,找出所有对self赋值的语句,提取对应的字段名。这种方法不需要实例化类,适合无法创建实例的场景(比如__init__依赖外部资源)。
二、实现get_members函数
针对给定的Mock类,要实现输入类本身时返回a和b,下面提供两种可行实现:
方法1:动态实例化提取(简单直接)
import inspect class Mock: def __init__(self, a): self.a = a def b(self): # 修正原代码中b方法缺少self参数的问题 pass def get_members(clz): """return all the members of clz and its instance, including static methods, class methods, instance level methods and fields e.g., given Mock, return a and b """ # 收集类层面的成员(过滤内置特殊成员) class_members = set() for name, _ in inspect.getmembers(clz): if not name.startswith('__'): class_members.add(name) # 动态创建实例,提取实例字段 instance_members = set() try: # 自动生成__init__所需的占位参数 sig = inspect.signature(clz.__init__) args = [None] * (len(sig.parameters) - 1) instance = clz(*args) instance_members = set(instance.__dict__.keys()) except Exception: # 实例化失败时跳过实例字段收集 pass # 合并并返回排序后的结果 return sorted(class_members.union(instance_members)) # 测试 print(get_members(Mock)) # 输出: ['a', 'b']
方法2:解析__init__源码(无需实例化)
import ast import inspect class Mock: def __init__(self, a): self.a = a def b(self): pass def get_instance_fields_from_init(clz): """从__init__方法中解析实例字段""" fields = set() if not hasattr(clz, '__init__'): return fields # 获取并解析__init__的源码 source_code = inspect.getsource(clz.__init__) tree = ast.parse(source_code) # 遍历语法树,找出self.xxx的赋值语句 for node in ast.walk(tree): if isinstance(node, ast.Assign): for target in node.targets: if (isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name) and target.value.id == 'self'): fields.add(target.attr) return fields def get_members(clz): """return all the members of clz and its instance, including static methods, class methods, instance level methods and fields e.g., given Mock, return a and b """ # 收集类层面的成员 class_members = set() for name, _ in inspect.getmembers(clz): if not name.startswith('__'): class_members.add(name) # 解析__init__获取实例字段 instance_fields = get_instance_fields_from_init(clz) # 合并并返回排序后的结果 return sorted(class_members.union(instance_fields)) # 测试 print(get_members(Mock)) # 输出: ['a', 'b']
注意事项
- 原
Mock类中的b()方法缺少self参数,不符合Python实例方法的定义,会导致调用实例的b()时出错,上述代码已修正该问题。 - 方法1中如果
__init__需要的参数无法用占位值填充(比如必须是特定类型),可根据实际场景调整参数传递逻辑。 - 方法2只能识别
__init__中直接对self赋值的字段,无法识别其他实例方法中动态添加的字段,这类场景仍需结合实例化方式处理。
内容的提问来源于stack exchange,提问作者Peaceful
相关产品推荐
相关产品推荐

