首页 > 解决方案 > 为什么 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

标签: execpython-3.7

解决方案


我找到了答案,尽管其中仍有一些晦涩难懂的地方。基本上,我不得不删除该行

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'?


推荐阅读