Search code examples
pythonpython-3.ximportipythonreload

IPython reloading different module?


I made a test of shadowing Python's built-in string module with my own module named 'string', to test module search path behavior. My custom string script has only print('string' * 2) for contents. It is located in the current directory as shown in code below.

Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: %pwd
Out[1]: 'C:\\Users\\stephen'

In [2]: import string

In [3]: string
Out[3]: <module 'string' from 'C:\\ProgramData\\Anaconda3\\lib\\string.py'>

In [4]: import imp

In [5]: imp.reload(string)
stringstring
Out[5]: <module 'string' from 'C:\\Users\\stephen\\string.py'>

Three questions about reload in IPython:

  1. Why did reload think the module it actually imported (the local string.py) had already been imported? Is it just the sameness of file name?
  2. Why did reload import a different module than the one already imported? Did it skip the check of sys.modules dictionary, which was checked first during original import?
  3. Why did reload/IPython/Python not know it had pulled a fast one here, switching one module for another?

Edit: In going back and forth trying to take care of Stack Overflow complaining about my code block, I inadvertently lost some of what I meant to say. Here is what I can remember: IPython is adding the built-in string module to sys.modules dictionary at startup (sys.modules is searched before sys.path), something the regular Python interactive prompt doesn't do. So I got a different behavior from the interactive prompt vs. IPython. With the interactive prompt, I always got the local string.py, since sys.path starts with current directory for module search. So, this much I understand about the difference between regular interactive (Anaconda) and IPython. The questions I listed are what remain confusing for me.


Solution

  • reload is supposed to repeat the process of locating the source code for the module it's reloading, and if it finds a different file from what the original import found, it's supposed to use the new file. After all, it needs to handle cases where a module was moved, or where a normal module was changed to a package or an extension module.

    reload is not supposed to look at sys.modules and stop if it finds something. If it did that, it would perform no reloading!

    The reason reload finds the local string.py file when the initial IPython-internal import didn't is because the import path has changed since the first import. You ran IPython in a way that doesn't cause Python itself to put the working directory on the module search path, and IPython imported the string module from the standard library under that configuration. Afterward, IPython placed the working directory on the module search path itself, mimicking regular interactive Python, so reload found the local string.py.