Python类静态方法用globals()写JSON失效但类外函数正常的原因
问题原因
核心差异是不同作用域下globals()返回的命名空间不一致:
- 定义在
resepi.py模块中的静态方法save,调用globals()时返回的是resepi.py模块本身的全局命名空间。你在交互命令行中创建的unit_35844等实例,存储在交互式终端的全局命名空间中,并不在resepi.py的模块全局空间里,所以遍历的时候找不到匹配的resepi类实例,最终返回空字典。 - 你在交互命令行直接定义的
save2函数,调用globals()时返回的就是当前交互终端的全局命名空间,里面正好包含了你创建的所有resepi实例,所以逻辑可以正常运行。
另外需要注意:你当前用globals()+eval()的实现方式风险很高,一旦全局空间里有不可序列化的对象、或者恶意构造的变量名,会直接触发安全问题或者运行报错,更推荐用类变量跟踪实例的实现方式。
修复方案
方案1:修改静态方法接收全局命名空间作为参数
修改resepi类的save方法:
@staticmethod def save(global_vars): all_units_info = {name: eval(name, global_vars).__dict__ for name in list(global_vars) if isinstance(eval(name, global_vars), resepi)} with open('resepi_log_all.json', 'w') as file: json.dump(all_units_info, file, indent=4) print(all_units_info)
调用时传入当前环境的全局变量即可:
resepi.save(globals())
方案2(更推荐):用类变量跟踪实例,完全避免操作全局命名空间
修改resepi类的实现:
class resepi: # 新增类变量存储所有实例 all_instances = [] def __init__ (self, serial_number): serial_number = int(serial_number) self.serial_number = serial_number self.ftp, self.type = ftp(serial_number) self.folder = 'C:\\Users\\17037\\Documents\\' + str(serial_number) # 初始化时把当前实例加入类变量 resepi.all_instances.append(self) ... @staticmethod def save(): all_units_info = {f"unit_{inst.serial_number}": inst.__dict__ for inst in resepi.all_instances} with open('resepi_log_all.json', 'w') as file: json.dump(all_units_info, file, indent=4) print(all_units_info)
这种实现不依赖外部全局命名空间,不管在哪调用resepi.save()都能正常导出所有实例。
内容的提问来源于stack exchange,提问作者Thomas K
相关产品推荐
相关产品推荐

