I'm trying to load functions from a script dynamically when I'm inside an ipython interactive shell. For example, suppose I have a python script like this:
# 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
def f():
print 'help me please.'
def g():
f()
Now if I run the script script.py, I'll be entering the interactive shell. If I type the following, my call to g() works:
execfile('routines.py')
g()
However, if I type the following, the call to g() fails:
Reload()
g()
I will get an error message saying that "global name f is not defined.", although I can still see that f and g are in the output when I type globals() in the interactive shell.
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
import IPython as ip
def Reload():
execfile('routines.py')
if __name__ == "__main__":
ip.embed()
And change routines.py to:
# 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. However this is not a preferred approach because I have to declare global names.
UPDATE 2:
It seems that the problem is independent of ipython. With the first version of routines.py if I start the python shell, and type the following by hand:
def Reload():
execfile('routines.py', {}, globals())
g()
The call to g() also fails. But the following works:
execfile('routines.py')
g()
As @Bakuriu said, importing is much preferred. 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). This means your functions are defined in local_dict
but not global_dict
.
When you then call g()
, it is executed using globals global_dict
and a fresh empty local dict. Since neither global_dict
or the new locals doesn't contain f
we get a name error. 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.
EDIT:
You noticed that local_dict
has both f
and g
, but global_dict
does not in the second example. 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()
; 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".