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 vals
to both exec
functions, you have provided the common namespace. The second argument to exec
is a dictionary to use for global references in any code that is executed. When the first statement is executed it creates fun
and stores it in the global namespace (vals
). Thus, when when main
tries to find fun
, it finds that it is not a local variable and so tries to lookup fun
in its globals (which is also vals
). Since fun
exists in vals
the lookup works and the function retrieved and called. If gave each exec
its own dict
then this wouldn't work. If you don't provide vals
then the current globals that exec
is called in is used as the globals (so this would still work).