Python如何通过另一变量值选择目标变量 替代eval的更优方案
你当前用eval的实现存在明显的安全隐患,执行效率也低,完全没必要用这种方案。Python没有原生指针概念,但有多种更安全、高效的方式可以实现「选中目标变量后,持续读取该变量最新值」的需求。
另外原代码有个小坑:用set作为自定义函数名会覆盖Python内置的set类型,后续如果要创建集合调用set()会直接报错,建议自定义函数改名为set_var之类的名称避免冲突。
方案1:最小代码改动,替换eval为作用域字典查询
Python的全局变量统一存储在globals()返回的字典中,键为变量名字符串,值为变量的当前引用。你已经在选择变量时存储了目标变量的名字符串,直接查询字典即可拿到对应值,完全不需要动态执行代码,从根源上避免了eval的代码注入风险,执行性能也高很多。
对应实现代码:
sel = 0 a = 1 b = 2 def set_var(index): if index == 0: return 'a' elif index == 1: return 'b' def get(sel): return globals()[sel] sel = set_var(0) print(get(sel)) # 输出1 a = 3 print(get(sel)) # 输出3 sel = set_var(1) print(get(sel)) # 输出2
运行结果和你预期完全一致。如果目标变量是外层函数的局部变量,换成查询locals()返回的字典即可。
方案2:闭包getter,无硬编码更灵活
如果不想硬编码变量名字符串,可以在选择变量时返回一个闭包函数,闭包会自动持有目标变量的引用,需要取值时直接调用闭包即可返回目标变量的最新值。这种方式不依赖变量名映射,哪怕目标是嵌套函数内的局部变量也能正常工作,适用场景更广。
对应实现代码:
a = 1 b = 2 def set_var(index): if index == 0: return lambda: a elif index == 1: return lambda: b # 存储的sel本质就是指向目标变量的"指针",调用即可拿到最新值 sel = set_var(0) print(sel()) # 输出1 a = 3 print(sel()) # 输出3 sel = set_var(1) print(sel()) # 输出2
方案3:面向对象场景直接用内置getattr
如果你要选择的目标是类/实例的属性,不需要额外封装,直接用Python内置的getattr函数即可,传入对象和属性名字符串就能拿到最新的属性值,属于安全的内置实现,不会执行任意代码。
示例代码:
class DataStore: def __init__(self): self.a = 1 self.b = 2 store = DataStore() sel_attr = 'a' print(getattr(store, sel_attr)) # 输出1 store.a = 3 print(getattr(store, sel_attr)) # 输出3
注意:非极端必要场景不要使用
eval/exec执行动态字符串代码。这类函数会无差别执行传入的任意Python代码,如果传入内容来自外部输入、不可信来源,很容易触发恶意代码执行,造成严重安全问题;同时动态解析执行代码的性能远低于内置的字典查询、函数调用、属性访问逻辑。
内容的提问来源于stack exchange,提问作者GePe

