3

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?

asked Jul 14, 2015 at 11:54
6
  • Can you give a specific example of "bizzare" behaviour? Commented Jul 14, 2015 at 11:57
  • Are you saying it's bizarre because of the circular importing or is it actually causing erratic behaviour when you run it? Can you show your code? Commented Jul 14, 2015 at 12:02
  • Bizarre as in the modules run as soon as imported, and then every time you call their main function? That would be my first guess. Please define the behavior. Commented Jul 14, 2015 at 12:04
  • I posted an answer explaining why you got that output. I may be able to help you understand how to do what you want, but at the moment your problem is abstract and unclear. Why do you want only a to run but you want the others imported? What's the use case? Commented Jul 14, 2015 at 12:24
  • @SuperBiasedMan I want my module a to be able to communicate with module c via b at the same time allowing module c to call functions or exceptions in module a Commented Jul 14, 2015 at 12:35

2 Answers 2

2

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
answered Jul 14, 2015 at 12:24
Sign up to request clarification or add additional context in comments.

7 Comments

why does module c import a again, when we had a import b and b import c in the first place
a.py has never been imported, it simply started running the script; c.py has every right to import a and run the things that happen within a.py once again. It is only once we reach import b for the second time that we have imported everything and we can essentially "skip" the imports (they aren't actually skipped, you get a reference but their code doesn't run). Take a look at my edit to see how you would probably expect it to run.
If you incorporate the if __name__ == "__main__": you can ensure that the other scripts (b & c) only run when you want them to: when you call b.main() and c.main(). Importing, however, will run everything not contained within a function.
Wow, thanks that helped. I have one more question- I was under the impression that when module c calls module a, it will be calling an instance of module a. So it should not have the name as main. Where am I wrong
If you wrap everything that you want to call within functions as shown you should be able to accomplish this; code will only execute when you call someModule.main(). Try implementing the code how I have shown at the bottom of my answer and see what I mean by adding in calls to b.main() and c.main().
|
1

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.

answered Jul 14, 2015 at 12:21

1 Comment

Thanks for the detailed explaination I would like to know how to achieve my desired behaviour

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.