tinkerbeast
tinkerbeast

Reputation: 2067

Issue with two instances of same module in python?

I have two modules as follows:

Module A - moda.py

import modb

x = None

def printx():
    global x
    print(x)

def main():
    global x
    x = 42
    printx()
    modb.printx()
    printx()

if __name__ == '__main__':
    main()

Module B - modb.py

import moda

def printx():
    moda.printx()

print('modb imported')

When I run python moda.py, the output I get is:

modb imported
42
None
42

I don't understand why the second print (coming from modb.printx()) is None. I thought python modules behaved as singletons. What am I missing?

Can someone please explain why the module imported in modb is not same as the original module moda?

Upvotes: 3

Views: 82

Answers (1)

Mad Physicist
Mad Physicist

Reputation: 114320

When an import statement is encountered, the interpreter looks for a corresponding key in sys.modules. If a key is found, it is bound to the name you requested. If not, a new empty module object is createdplaced in sys.modules, , and then populated. The reason for doing it like that is exactly to avoid infinite loops with circular imports.

When you run a module, it is imported under the name __main__. You ca

Here is the sequence of events when you run moda as a script:

  1. Start of load of moda.py as sys.modules['__main__']. At this point, this is just an empty namespace
  2. import modb encountered in moda.py. New empty namespace created for sys.modules['modb'].
  3. import moda encountered in modb.py. New empty namespace created for sys.modules['moda']. Notice that this is not the same object as sys.modules['__main__'] in step 1.
  4. import modb encountered in moda.py. Since sys.modules['modb'] exists, it is bound to that name in moda
  5. Since moda.py is currently being loaded under the name moda, it finishes populating its namespace without running the import guard.
  6. modb.py finishes populating its namespace (from step 2.) and runs print('modb loaded').
  7. __main__ defined in moda.py finishes populating its namespace (from step 1.) and runs the import guard.

Hopefully this helps you visualize what happens. You have three modules, not two, that were loaded, because moda is loaded under two different names, and as two entirely different module objects.

The import guard in __main__ calls __main__.main, which does the following:

  1. Set __main__.x = 42 (moda.x is still None)
  2. __main__.printx prints __main__.x, which is 42
  3. modb.printx calls moda.printx, which prints moda.x, which is None.
  4. __main__.printx prints __main__.x again, which is still 42.

Upvotes: 3

Related Questions