如何获取Python类所有变量(含未赋值项)实现动态字段校验
解决方案
Python 3.6+ 原生支持通过类的__annotations__属性获取所有通过类型注解声明的类字段,无论这个字段有没有赋值默认值,刚好匹配需求,不需要依赖任何第三方库。
核心逻辑
你定义的类中,所有形如height: int、is_alive: bool = True的字段,都会被记录到类的__annotations__字典中,键为字段名,值为字段标注的类型。校验时只需要区分三类字段即可:
- 所有声明过的字段:从
__annotations__中获取 - 有默认值的字段:存在于类本身的
__dict__属性中 - 已经通过链式方法手动赋值的字段:存在于实例的
__dict__属性中
只要某个声明过的字段既没有默认值,也没有被手动赋值,就属于校验不通过的缺失字段。
完整实现代码
class Query: height: int weight: int age: int name: str is_alive: bool = True def of_height(self, height): self.height = height return self def with_name(self, name): self.name = name return self def of_weight(self, weight): self.weight = weight return self def of_age(self, age): self.age = age return self def validate(self): # 获取当前类所有声明的注解字段 declared_fields = self.__class__.__annotations__.keys() missing = [] for field in declared_fields: # 字段既没有手动赋值,也没有默认值则标记为缺失 if field not in self.__dict__ and field not in self.__class__.__dict__: missing.append(field) if missing: raise ValueError(f"缺失必填查询字段: {', '.join(missing)}") # 校验通过后可在这里编写后续API请求构造逻辑 return True
效果测试
# 场景1:仅赋值height、name,缺失weight、age q = Query() q.of_height(175).with_name("Alice") try: q.validate() except ValueError as e: print(e) # 输出:缺失必填查询字段: weight, age # 场景2:所有必填字段赋值完成 q2 = Query() q2.of_height(175).with_name("Alice").of_weight(65).of_age(25) q2.validate() # 校验正常通过 print(q2.is_alive) # 输出:True,正常读取类默认值
扩展适配场景
- 支持类继承:如果你的Query类会被其他类继承,需要把父类声明的字段也纳入校验,只需要替换validate中获取声明字段的逻辑,顺着类的继承链(
__mro__)合并所有父类的注解即可:
调用时传入def get_all_declared_fields(cls): fields = {} # 反向遍历继承链,保证子类字段覆盖父类同名字段 for klass in reversed(cls.__mro__): fields.update(getattr(klass, "__annotations__", {})) return fields.keys()self.__class__就能拿到所有继承来的声明字段。 - 适配无注解的类属性:如果后续有直接赋值、没写类型注解的类属性需要被校验,只需要在收集声明字段时,把类
__dict__中不是方法、不是双下划线特殊属性的键合并进去即可。
这个方案完全动态,后续新增查询字段时,只要按照现有风格写类型注解:如果是必填字段就只写类型不赋值,如果是可选字段就直接给默认值,validate方法不需要做任何修改。
内容的提问来源于stack exchange,提问作者Antrikshy
相关产品推荐
相关产品推荐

