Python动态创建类实例属性时能否避免使用exec()函数?
解决方案
核心替代方案是使用Python内置的setattr()函数实现动态属性设置,完全可以达到和exec一致的效果,且无代码注入风险。
原有代码问题修正
在给出实现前先修正你现有代码的明显问题:
student类__init__方法存在笔误:参数为Grade_,赋值时写的是self.Grade_=Grade,右侧Grade未定义,运行会直接报错。Classroom继承student不符合面向对象设计逻辑:继承对应"is-a"关系,教室不属于学生,应该使用组合关系,无需继承student类。- 原有循环逻辑错误:遍历的是分数列表,把分数值当做姓名拼接属性名,和你预期的
self.Student_[姓名]调用逻辑不符,需要同时遍历姓名列表和分数列表的配对。
完整实现代码
class student(): def __init__(self, Name_, Grade_): self.Name = Name_ self.Grade = Grade_ # 修正笔误 # 其他原有代码 class Classroom(): # 移除不合理的student继承 def __init__(self, Class_Name_, Class_Supervisoir_, list_of_students_Names_, List_of_Students_Grades_): self.Class_Name = Class_Name_ self.Class_Supervisoir = Class_Supervisoir_ self.list_of_students_Names = list_of_students_Names_ self.List_of_Students_Grades = List_of_Students_Grades_ # 配对遍历学生姓名和对应分数 for name, grade in zip(list_of_students_Names_, List_of_Students_Grades_): # 动态设置实例属性,效果和exec完全一致,无安全风险 setattr(self, f"Student_{name}", student(name, grade))
实现后你就可以按预期的方式调用:实例化Classroom后,直接用class1.Student_Mark、class1.Student_Peter访问对应的学生实例。
可选优化
如果后续需要批量操作所有学生,可以额外加一个字典存储所有学生实例,方便遍历:
class Classroom(): def __init__(self, Class_Name_, Class_Supervisoir_, list_of_students_Names_, List_of_Students_Grades_): self.Class_Name = Class_Name_ self.Class_Supervisoir = Class_Supervisoir_ self.list_of_students_Names = list_of_students_Names_ self.List_of_Students_Grades = List_of_Students_Grades_ self.students = {} # 存储所有学生实例的字典 for name, grade in zip(list_of_students_Names_, List_of_Students_Grades_): stu_instance = student(name, grade) self.students[name] = stu_instance setattr(self, f"Student_{name}", stu_instance)
需要批量处理时直接遍历self.students.values()即可,不需要筛选属性前缀。
安全性说明
setattr是Python官方提供的原生动态属性设置方法,只会将输入作为纯属性名和属性值处理,不会执行任何字符串内置的恶意代码,完全规避了exec的代码注入风险,可以放心在生产环境使用。
内容的提问来源于stack exchange,提问作者MoS
相关产品推荐
相关产品推荐

