Python函数递归调用时exec创建的全局变量丢失问题求助
问题原因
- 你调用
exec()时同时传入了全局作用域、本地作用域两个字典参数,Python默认会将exec内的赋值操作写入你传入的本地作用域(locals()),因此不会出现在全局变量查询结果中。 - 你当前用字符串拼接构造exec语句的写法存在注入风险,如果用户输入带双引号、特殊转义符等内容,会直接导致代码报错甚至被插入执行恶意代码,非常不推荐。
解决办法
根据你的需求,提供三种可选实现方案:
方案1:调整exec参数实现全局赋值
如果一定要用exec实现动态赋值,只需要去掉第三个locals参数,exec内的赋值就会默认写入全局作用域,同时改用f-string+repr()处理输入内容,避免拼接出错:
class Item(): def printVal(self,value): return value def func(self): userInput = input("Input string:") if userInput!="0": # 去掉locals参数,赋值默认写入全局作用域 exec(f"a = self.printVal({repr(userInput)})", globals()) else: return print(globals()) self.func() if __name__ == "__main__": item = Item() item.func()
方案2:直接操作全局字典(更安全,支持动态添加任意变量)
如果后续要按需添加任意名称的变量,直接修改globals()字典比用exec更安全可控,完全规避动态代码执行的风险:
if userInput!="0": var_name = "a" # 可替换为任意你需要的变量名 var_value = self.printVal(userInput) globals()[var_name] = var_value
只要修改var_name的值,就可以动态添加任意名称的全局变量,符合你后续拓展的需求。
方案3:用实例属性存储(更符合面向对象规范)
如果你只需要在Item类的实例递归调用时读取变量,不需要真的全局可用,把变量存在实例属性里是更合理的选择,不会污染全局作用域:
if userInput!="0": var_name = "a" var_value = self.printVal(userInput) # 给实例动态添加属性 setattr(self, var_name, var_value) # 后续递归调用时直接读取即可,比如 print(self.a)
内容的提问来源于stack exchange,提问作者user57284
相关产品推荐
相关产品推荐

