With this test code using exec (using Python 3.4):
vals = {}
exec('def fun(): print("Hello from fun")', vals)
exec('def main(): fun()', vals)
vals['main']()
The output is:
Hello from fun
But I did not expect this to work, since I assumed that fun and main where interpreted as separate code pieces without a common namespace to resolve the reference in main to fun.
So how can execution of main resolve the reference to fun?
Addition based understanding the issue. With print of id for vals and globals, it becomes clear that the two functions sees the same globals:
vals = {}
print('id(vals):', id(vals))
exec('def fun(): print("fun id(globals()):", id(globals())); print("Hello from fun")', vals)
exec('def main(): print("main id(globals()):", id(globals())); fun()', vals)
vals['main']()
Which gives:
id(vals): 32271016
main id(globals()): 32271016
fun id(globals()): 32271016
Hello from fun
So the vals is used as globals for the code in exec, thus giving the connection, as @Dunes and other comments described. Thanks.
By providing
valsto bothexecfunctions, you have provided the common namespace. The second argument toexecis a dictionary to use for global references in any code that is executed. When the first statement is executed it createsfunand stores it in the global namespace (vals). Thus, when whenmaintries to findfun, it finds that it is not a local variable and so tries to lookupfunin its globals (which is alsovals). Sincefunexists invalsthe lookup works and the function retrieved and called. If gave eachexecits owndictthen this wouldn't work. If you don't providevalsthen the current globals thatexecis called in is used as the globals (so this would still work).