Reputation: 441
I am working on a project where I have three python modules (a.py
, b.py
and c.py
).
Module a
is calling module b
, module b
is calling module c
, and module c
is calling module a
. But the behaviour is very bizzare when it runs.
Here are my three modules:
a.py
print('module a')
def a() :
print('inside a')
return True
import b
b.b()
b.py
print('module b')
def b() :
print('inside b')
return True
import c
c.c()
c.py
print('module c')
def c() :
print('inside c')
return True
import a
a.a()
When I run a.py
, the output observed is :
module a
module b
module c
module a
inside b
inside a
inside c
inside b
Whereas the expected behavior is:
module a
module b
module c
module a
inside b
Why does this happen? Is there an alternative way for such an implementation?
Upvotes: 3
Views: 1282
Reputation: 2115
This has to do with stack frames and how functions and imports are called.
You start by running a.py.
'module a'
First thing that happens: import b
:
'module b'
Within b, c.py is imported:
'module c'
Module c imports a, and we get:
'module a'
b has already been imported from running a.py in the first place, so this call of import b
is passed (we do not re-import b.py). We then see the effects of calling b.b()
, the next statement:
inside b
And we return to c.py's frame, where we call a.a()
:
inside a
c.py has run its course; next we jump back to b.py, where we left off (right after importing), and call c.c()
:
inside c
Now b.py has finished running as well. Finally we return to the a.py frame from which we ran the program, and call b.b()
:
inside b
Hope this helps explain this behavior. Here's an example of how you could rectify this problem and get your desired output:
a.py:
print("module a")
import b
def main():
b.b()
def a():
print("inside a")
if __name__ == "__main__":
main()
b.py:
print("module b")
import c
def main():
c.c()
def b():
print("inside b")
if __name__ == "__main__":
main()
c.py:
print("module c")
import a
def main():
a.a()
def c():
print("inside c")
if __name__ == "__main__":
main()
Here's a link to explain what happens with the if __name__ == "__main__": main()
call. Essentially it will only run the main()
function for each script if that is the script that is built & run in the first place. In this way, you get the desired output:
module a
module b
module c
module a
inside b
Upvotes: 2
Reputation: 9969
I think the key misunderstanding is that you don't expect all the modules to run after their imports, but they do. They get interrupted mid script to do another import but they will return to finish out the commands.
So what ends up happening is: (I'm removing the function declarations, just for clarity)
print('module a')
import b
>>> importing b
print('module b')
import c
>>> importing c
print('module c')
import a
>>> importing a
print('module a')
import b
>>> Doesn't reimport b
b.b()
a.a()
c.c()
b.b()
So to just show the order of commands without the imports and nesting:
print('module a')
print('module b')
print('module c')
print('module a')
b.b()
a.a()
c.c()
b.b()
And this does match your actual output.
Upvotes: 1