当我在ipython交互式shell中时,我正试图动态地从脚本加载函数。例如,假设我有一个像这样的python脚本:
# script.py
import IPython as ip
def Reload():
execfile('routines.py', {}, globals())
if __name__ == "__main__":
ip.embed()
假设文件routines.py是这样的:
# routines.py
def f():
print 'help me please.'
def g():
f()
现在,如果我运行脚本script.py,我将进入交互式shell。如果我输入以下内容,我对g()的调用就可以了:
execfile('routines.py')
g()
但是,如果我键入以下内容,则对g()的调用将失败:
Reload()
g()
我会收到一条错误消息,指出“全局名称f未定义。”,虽然我在交互式中键入globals()时仍然可以看到f和g在输出中外壳
这两者有什么区别?
更新:
以下工作,但它不是首选解决方案,所以我希望有一个更好的解决方案来解决上述问题。
如果我将script.py更改为:
# script.py
import IPython as ip
def Reload():
execfile('routines.py')
if __name__ == "__main__":
ip.embed()
将routines.py更改为:
# routines.py
global f
global g
def f():
print 'help me please.'
def g():
f()
然后,如果我在交互式shell中调用Reload()然后调用g(),它就可以工作。但是,这不是首选方法,因为我必须声明全局名称。
更新2:
似乎问题与ipython无关。如果我启动python shell,则使用routines.py的第一个版本,并手动输入以下内容:
def Reload():
execfile('routines.py', {}, globals())
g()
对g()的调用也失败了。但是以下工作:
execfile('routines.py')
g()
答案 0 :(得分:0)
正如@Bakuriu所说,进口是首选。忽略它,你想要的是什么
def Reload():
execfile('routines.py', globals())
让我们澄清你的例子,说明它为什么不起作用。
# Setup the namespace to use for execfile
global_dict = {}
local_dict = globals()
execfile('routines.py', global_dict, local_dict)
g() # raises NameError
由于您将两个不同的词组传递给execfile
,因此该文件的执行就像它在类定义(from the docs)中一样。这意味着您的功能定义在local_dict
但不是global_dict
。
当你再调用g()
时,它将使用全局global_dict
和一个新的空本地字典来执行。由于global_dict
或新本地人都不包含f
,因此我们会收到名称错误。相反,我们正在调用execfile('routines.py', globals())
,global_dict = globals()
和local_dict = globals()
,因此在f
的全局变量中定义了g
。
编辑:
您注意到local_dict
同时包含f
和g
,但第二个示例中没有global_dict
。定义任何变量而不明确地将其标记为全局变量将始终生成局部变量,这也适用于模块!通常情况下,模块具有locals() == globals()
;但是,我们通过使用不同的本地和全球决策来打破这一标准。这就是我说的时候的意思"文件的执行就像是在类定义中一样#34;。