[英]Functions defined in dynamically-loaded scripts cannot refer to each other
I'm trying to load functions from a script dynamically when I'm inside an ipython interactive shell. 当我在ipython交互式外壳中时,尝试从脚本动态加载函数。 For example, suppose I have a python script like this:
例如,假设我有一个像这样的python脚本:
# script.py
import IPython as ip
def Reload():
execfile('routines.py', {}, globals())
if __name__ == "__main__":
ip.embed()
Suppose the file routines.py is like this: 假设文件routines.py如下所示:
# routines.py
def f():
print 'help me please.'
def g():
f()
Now if I run the script script.py, I'll be entering the interactive shell. 现在,如果我运行脚本script.py,我将进入交互式shell。 If I type the following, my call to g() works:
如果键入以下内容,则对g()的调用有效:
execfile('routines.py')
g()
However, if I type the following, the call to g() fails: 但是,如果键入以下内容,则对g()的调用将失败:
Reload()
g()
I will get an error message saying that "global name f is not defined." 我将收到一条错误消息,指出“未定义全局名称f”。 , although I can still see that f and g are in the output when I type globals() in the interactive shell.
,尽管当我在交互式shell中键入globals()时,仍然可以看到f和g在输出中。
What's the difference of these two? 这两者有什么区别?
UPDATE: 更新:
The following works, however it's not a preferred solution so I would like to have a better solution for the problem above. 以下工作有效,但是它不是首选解决方案,因此我想针对上述问题提供更好的解决方案。
If I change script.py to: 如果我将script.py更改为:
# script.py
import IPython as ip
def Reload():
execfile('routines.py')
if __name__ == "__main__":
ip.embed()
And change routines.py to: 并将例程.py更改为:
# routines.py
global f
global g
def f():
print 'help me please.'
def g():
f()
Then if I call Reload() in the interactive shell and then call g(), it works. 然后,如果我在交互式外壳程序中调用Reload()然后再调用g(),它就可以工作。 However this is not a preferred approach because I have to declare global names.
但是,这不是首选方法,因为我必须声明全局名称。
UPDATE 2: 更新2:
It seems that the problem is independent of ipython. 看来问题独立于ipython。 With the first version of routines.py if I start the python shell, and type the following by hand:
如果我启动python shell,则使用常规程序的第一个版本,并手动键入以下内容:
def Reload():
execfile('routines.py', {}, globals())
g()
The call to g() also fails. 对g()的调用也失败。 But the following works:
但是以下工作原理:
execfile('routines.py')
g()
As @Bakuriu said, importing is much preferred. 正如@Bakuriu所说,导入是首选。 Ignoring that, what you want is
忽略这一点,你想要的是
def Reload():
execfile('routines.py', globals())
Lets clarify your example to show why it does not work. 让我们澄清您的示例,以说明为什么它不起作用。
# Setup the namespace to use for execfile
global_dict = {}
local_dict = globals()
execfile('routines.py', global_dict, local_dict)
g() # raises NameError
Since you are passing two different dicts to execfile
, the file is executed as if it were in a class definition ( from the docs ). 由于您要将两个不同的字典传递给
execfile
,因此文件的执行就像在类定义中一样( 来自docs )。 This means your functions are defined in local_dict
but not global_dict
. 这意味着您的函数是在
local_dict
中定义的,而不是在global_dict
中定义的。
When you then call g()
, it is executed using globals global_dict
and a fresh empty local dict. 然后调用
g()
,将使用globals global_dict
和一个空的本地dict来执行它。 Since neither global_dict
or the new locals doesn't contain f
we get a name error. 由于
global_dict
或新的本地人都不包含f
,因此会出现名称错误。 By instead calling execfile('routines.py', globals())
, we are using global_dict = globals()
and local_dict = globals()
so f
is defined in g
's globals. 通过改为调用
execfile('routines.py', globals())
,我们使用了global_dict = globals()
和local_dict = globals()
因此f
在g
的globals中定义。
EDIT: 编辑:
You noticed that local_dict
has both f
and g
, but global_dict
does not in the second example. 您注意到
local_dict
具有f
和g
,但是在第二个示例中global_dict
没有。 Defining any variable without explicitly marking it global will always make a local variable, this applies to modules too! 在没有显式标记全局变量的情况下定义任何变量将始终创建局部变量,这也适用于模块! It just so happens that normally a module has
locals() == globals()
; 碰巧的是,通常一个模块具有
locals() == globals()
; however, we broke this standard by using different local and global dicts. 但是,我们通过使用不同的本地和全局指令来打破此标准。 This is what I meant when I said "the file is executed as if it were in a class definition".
这就是我说“文件就像在类定义中一样执行”时的意思。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.