Python3中exec()无法从外部.py文件导入变量问题排查
Python2.7转3.6:exec执行外部脚本后变量未定义问题
问题说明
将Python2.7脚本迁移至3.6时,原本用于读取外部rules.py文件并导入变量的函数报错,提示notify_rules未定义。
原加载函数代码
def _load_rules(old_hash=''): # Determine if the rules file has changed, and if so reload it rules = open(rules_file, 'r').read() new_hash = md5(b'rules').hexdigest() if new_hash != old_hash: exec(rules) # C{ignore_rules} and C{notify_rules} come from the script execution return (new_hash, ignore_rules, notify_rules) return (old_hash, None, None)
外部rules.py代码
import datetime import re notify_rules = \ [{'event': 'failure', 'access_point': None, 'expression': re.compile(r'some_regex'), 'addresses': ['some_email@email.com']}, {'event': 'failure', 'access_point': 'access_point_', 'addresses': ['some_email@email.com']}, ignore_rules = \ [{'access_point': 'something'}, {'access_point': 'something'}, {'access_point': 'something'}, {'access_point': 'something'},]
报错信息
File "/app/eam/gaic/ai_mon/monitoring.py", line 174, in _load_rules return (new_hash, notify_rules, ignore_rules) builtins.NameError: name 'notify_rules' is not defined
问题原因及解决方案
1. 修复rules.py的语法错误
原rules.py中notify_rules的列表未闭合(缺少]),导致exec执行脚本时直接失败,变量根本没被定义。修正后的rules.py:
import datetime import re notify_rules = \ [{'event': 'failure', 'access_point': None, 'expression': re.compile(r'some_regex'), 'addresses': ['some_email@email.com']}, {'event': 'failure', 'access_point': 'access_point_', 'addresses': ['some_email@email.com']}] # 补充闭合的] ignore_rules = \ [{'access_point': 'something'}, {'access_point': 'something'}, {'access_point': 'something'}, {'access_point': 'something'},]
2. 适配Python3中exec的作用域规则
Python3里exec默认不会将执行产生的变量注入当前函数作用域,需要显式传递命名空间字典来保存变量。同时原代码的哈希计算逻辑错误(固定对b'rules'取哈希,无法检测文件变更),一并修正:
修改后的_load_rules函数:
import hashlib # 需要导入hashlib def _load_rules(old_hash=''): # 检测规则文件是否变更,变更则重新加载 with open(rules_file, 'r', encoding='utf-8') as f: rules = f.read() # 对文件内容计算哈希,正确检测文件变更 new_hash = hashlib.md5(rules.encode('utf-8')).hexdigest() if new_hash != old_hash: # 创建命名空间字典,用于保存exec执行后的变量 local_vars = {} exec(rules, globals(), local_vars) # 从命名空间字典中取出需要的变量 return (new_hash, local_vars['notify_rules'], local_vars['ignore_rules']) return (old_hash, None, None)
关键说明
- 使用
with语句打开文件,更安全且自动关闭文件句柄 - 修正哈希计算逻辑:基于读取的文件内容生成哈希,确保能正确检测文件变更
- 通过
exec(rules, globals(), local_vars)将执行结果存入local_vars,再从字典中提取变量,适配Python3的作用域规则
内容的提问来源于stack exchange,提问作者iNeedScissors61
相关产品推荐
相关产品推荐

