exec - 为什么 dows exec() 函数可以在原始代码中工作,但不能在 Python 3.7 中的函数或类中工作?
问题描述
下面我展示了 Python 3.7 中 exec() 函数的 2 个使用示例,一个在类中,一个在原始代码中。只有后者才能正常工作。有人可以向我解释可能的原因并提出解决方案吗?
#!/usr/bin/env python
import pandas as pd
################################# exec() WITHIN A CLASS ###################################
class Test:
def __init__(self):
pass
def f(self):
pose, frame, min_complexE, min_lEfree, best_structvar, best_conf, complexE, ligandE_bound, proteinE_bound, \
min_lEfree = [None] * 10
table = pd.read_table("sample_scores.txt", delim_whitespace=True, skiprows=[0]) # 1st line is a comment
table_columns = table.columns
for i, row in table.iterrows():
# Variable assignemnt
for varname in ["pose", "frame", "min_complexE", "min_lEfree", "best_structvar", "best_conf",
"complexE", "ligandE_bound", "proteinE_bound", "min_lEfree", "Eint"]:
if varname in table_columns:
exec("%s = %s" % (varname, row[varname]), globals(), globals())
else:
exec("%s = None" % (varname), globals(), globals())
print("proteinE_bound within class =", proteinE_bound)
def caller1(self):
self.f()
def caller2(self):
self.caller1()
Test().caller2()
################################# exec() IN RAW CODE ###################################
pose, frame, min_complexE, min_lEfree, best_structvar, best_conf, complexE, ligandE_bound, proteinE_bound, \
min_lEfree = [None] * 10
table = pd.read_table("sample_scores.txt", delim_whitespace=True, skiprows=[0]) # 1st line is a comment
table_columns = table.columns
for i, row in table.iterrows():
# Variable assignemnt
for varname in ["pose", "frame", "min_complexE", "min_lEfree", "best_structvar", "best_conf",
"complexE", "ligandE_bound", "proteinE_bound", "min_lEfree", "Eint"]:
if varname in table_columns:
exec("%s = %s" % (varname, row[varname]), globals(), globals())
else:
exec("%s = None" % (varname), globals(), globals())
print("proteinE_bound as raw code =", proteinE_bound)
“sample_scores.txt”文件的内容是:
# Contains all results. For the best result for each compound please refer to file BEST_RESULTS.
molname Eint complexE ligandE_bound proteinE_bound stereoisomer ionstate tautomer pose frame
LEM00001847 -63.000496 -17406.593934 -84.868633 -17258.724804 1 1 1 1 571
LEM00001847 -62.412897 -17474.918135 -64.778724 -17347.726515 1 1 1 1 171
LEM00001847 -61.249384 -17423.452346 -82.875735 -17279.327226 1 1 1 1 531
解决方案
我找到了答案,尽管其中仍有一些晦涩难懂的地方。基本上,我不得不删除该行
pose, frame, min_complexE, min_lEfree, best_structvar, best_conf, complexE, ligandE_bound, proteinE_bound, \
min_lEfree = [None] * 10
我在其中初始化了要由 exec() 分配的变量。如果这些变量不预先存在,那么它们会成功添加到 globals() 中,并且可以在函数中作为单独的变量进行访问。
现在模糊点:
1)即使我将这 10 个变量初始化为 None,在 for 循环的每次迭代中,它们的值都会在 globals() 字典中更新,但当我将它们的名称作为单个变量调用时不会更新。
2)根据 docs.python.org exec(__object, __globals=..., __locals=...)
。似乎只有给定的 '__globals' 字典会使用新变量进行更新。所以虽然在我上面的代码中我使用
exec("%s = %s" % (varname, row[varname]), globals(), globals())
这也有效
exec("%s = %s" % (varname, row[varname]), locals(), globals())
在我的理解中,后者是正确的方法,因为您希望在函数的上下文中创建这些变量,即作为局部变量。但是为什么 exec() 更新给定的 '__globals' 而不是给定的 '__locals'?
推荐阅读
- rust - `for...in` 循环中的 Rust 借用规则
- javascript - 将多个 api 链接传入服务并将所有结果放入数组
- c# - IEnumerator While 循环:Mathf.Lerp while 游戏继续运行
- ios - 如何在 web 视图中实现 Sign-In-With-Apple?
- firebase - Flutter 方法在 null 上被调用。接收方:空
- ruby-on-rails - 为多态 Rails 模型构建物化视图或使用 ActiveRecord
- python - 在 Python 中从 CSV 加载迭代 URL
- javascript - 如何设置间隔,清除它,使用相同的确切 ID 重置间隔
- python - 有没有一种好方法可以将布尔数组存储到 python 中的文件或数据库中?
- css - Sass 编译问题