This code was picked up from an answer in this thread What does if __name__ == "__main__": do?
# Suppose this is foo3.py.
def functionA():
print("a1")
from foo3 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
print("m1")
functionA()
print("m2")
print("t2")
I think the code is executed as follows (when executed as main python3 foo3.py):
1. Prints t1
2. Prints m1
3. Enters functionA and prints a1
4. Imports functionB from foo3, thus running foo3 again. Goes back to step 1
Can you help me correct my analysis?
It does not "run foo3
again", it runs the foo3.py
script again. The first time foo3.py
was running was to produce the module __main__
, the second time to produce the module foo3.py
.
The behaviour is in fact (almost) as if you had a file named __main__.py
and another named foo3.py
both with these exact same content and you then run python __main__.py
. This is what is happening.
Only, Python fakes it so that it looks as if the program started from a script named __main__.py
no matter what the actual Python file was. The only telltale sign to contrary is that __file__
would tell the filename of the actual script, i.e. /spam/ham/eggs/foo3.py
.
The reason why it does not go to an infinite loop is that import
looks for a module with the given name in sys.modules
- if it is already present there it does not execute any new files. Upon startup Python will create an entry for __main__
in sys.modules
, and the code of the startup script (foo3.py
) is executed within the scope of this module.
Then when it executes the statement import foo3
it will check if foo3
has an entry in sys.modules
. As it is not there, a new empty module named foo3
is created, placed into sys.modules
, and the code of foo3.py
is executed within the scope of this new empty module.
It eventually executes the import
2nd time. This time there is foo3
in sys.modules
, so importing does not create or load any more scripts, just returns the already-loaded module.
To get the "infinite" loop you can delete the already-imported module reference from sys.module
prior to importing foo3
again:
import sys
def functionA():
print("a1")
if 'foo3' in sys.modules:
del sys.modules['foo3']
from foo3 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
print("m1")
functionA()
print("m2")
print("t2")
And when run you'll get
[....]
File ".../foo3.py", line 7, in functionA
from foo3 import functionB
File ".../foo3.py", line 17, in <module>
functionA()
File ".../foo3.py", line 7, in functionA
from foo3 import functionB
RuntimeError: maximum recursion depth exceeded while calling a Python object