To preface, I think I may have figured out how to get this code working (based on Changing module variables after import), but my question is really about why the following behavior occurs so I can understand what to not do in the future.
I have three files. The first is mod1.py:
# mod1.py
import mod2
var1A = None
def func1A():
global var1
var1 = 'A'
mod2.func2()
def func1B():
global var1
print var1
if __name__ == '__main__':
func1A()
Next I have mod2.py:
# mod2.py
import mod1
def func2():
mod1.func1B()
Finally I have driver.py:
# driver.py
import mod1
if __name__ == '__main__':
mod1.func1A()
If I execute the command python mod1.py then the output is None. Based on the link I referenced above, it seems that there is some distinction between mod1.py being imported as __main__ and mod1.py being imported from mod2.py. Therefore, I created driver.py. If I execute the command python driver.py then I get the expected output: A. I sort of see the difference, but I don’t really see the mechanism or the reason for it. How and why does this happen? It seems counterintuitive that the same module would exist twice. If I execute python mod1.py, would it be possible to access the variables in the __main__ version of mod1.py instead of the variables in the version imported by mod2.py?
The
__name__variable always contains the name of the module, except when the file has been loaded into the interpreter as a script instead. Then that variable is set to the string'__main__'instead.After all, the script is then run as the main file of the whole program, everything else are modules imported directly or indirectly by that main file. By testing the
__name__variable, you can thus detect if a file has been imported as a module, or was run directly.Internally, modules are given a namespace dictionary, which is stored as part of the metadata for each module, in
sys.modules. The main file, the executed script, is stored in that same structure as'__main__'.But when you import a file as a module, python first looks in
sys.modulesto see if that module has already been imported before. So,import mod1means that we first look insys.modulesfor themod1module. It’ll create a new module structure with a namespace ifmod1isn’t there yet.So, if you both run
mod1.pyas the main file, and later import it as a python module, it’ll get two namespace entries insys.modules. One as'__main__', then later as'mod1'. These two namespaces are completely separate. Your globalvar1is stored insys.modules['__main__'], butfunc1Bis looking insys.modules['mod1']forvar1, where it isNone.But when you use
python driver.py,driver.pybecomes the'__main__'main file of the program, andmod1will be imported just once into thesys.modules['mod1']structure. This time round,func1Astoresvar1in thesys.modules['mod1']structure, and that’s whatfunc1Bwill find.