Functions defined in dynamically-loaded scripts cannot refer to each other
Question: 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()
    


Answer: 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](https://docs.python.org/2/library/functions.html#execfile)). 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".

