如何导入模块并更改模块内的变量值并执行它

5

我有一个模块需要导入并且更改导入实例中的特定变量值,然后执行它。

请注意:由于遗留原因,我无法对被导入的模块进行任何修改。

这是我想做的事情:

假设我想要导入的模块名为a.py,它看起来像这样:

var1 = 1
var2 = 2

if __name__ == '__main__':
    print var1+var2

现在我正在b.py中导入它,作为调用者脚本。 我尝试导入它,更改变量var1的值,并使用以下方式通过runpy运行它作为主程序。

import runpy
import a

a.var1 = 2
result = runpy._run_module_as_main(a.__name__)

但是这个程序只会打印结果 3,而不是期望的 4。有没有其他方法可以实现这个目标(除了使用 runpy)而不需要更改 a.py 中的任何内容?可以使用第三方模块,只要我不必修改导入的模块即可。我正在使用 Python 2.6 版本。

1
如果你真的想做这件事,我相信你需要ast模块。 - Wayne Werner
@WayneWerner 请告诉我如何操作。 - MohitC
@XanderLuciano 只要不需要修改 a.py 文件,任何方法都可以。 - MohitC
1
@MohitC 那么你可能想要做的就是在你自己的代码中复制if __name__ == "__main__":块内部的任何内容,并像你已经在做的那样简单地改变值。除非它被糟糕地编写,否则这个块中不应该有太多的代码。 - Wayne Werner
这里有一个想法。我相信runpy模块可以归结为exec .. in ..。尝试复制该功能,并传入一个对“var1”值更改免疫的字典。 - UltraInstinct
显示剩余7条评论
1个回答

3
这是我在评论中提出的具体实现示例:
#File temp.py
var1 = 1
var2 = 2

if __name__ == '__main__':
    print var1+var2

我是通过另一个文件run.py来调用它的。关键在于有另一个类似于字典的类,它不会受到模块导入/运行时可能改变的变量的任何更改的影响。这个字典包含你想要更改值的变量。

#File: run.py
class UpdatedDict(dict):
    def __setitem__(self, key, value):
        if key != "var1":
            super(UpdatedDict, self).__setitem__(key, value)

u = UpdatedDict({"var1": 10, '__name__': '__main__'})
exec open("temp.py").read() in u  #u here is the globals() for the module.

输出

~/Temp$ python run.py
12  #Yay!

注意:这只是一个快速而简陋的实现,只是为了向您展示可以完成此操作的方式。我建议查看runpy并使此代码更加健壮。就目前而言,它是“hackish”的一个正确定义。

太好了!非常感谢你。 :) 你可能为我节省了2天的时间,因为我不需要浏览所有旧脚本并对它们进行必要的更改,而不会破坏其余的架构。 - MohitC
虽然这样做可以起作用,但由此节省的任何工作都很可能被人们处理它时产生的额外工作所抵消。它创建了极其紧密的、非本地耦合,通过阅读修改的代码无法检测到,使得更改该系统的任何部分变得更加困难。当他们的赋值语句完全被忽略时,人们会感到非常困惑。 - user2357112
@user2357112 我完全同意!我希望原帖作者能够意识到你刚才说的话。 - UltraInstinct
我明白并同意你们两个的观点,但同时,这将适用于我的特定用例,而不会在系统中造成任何混乱。谢谢。 - MohitC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接