Why can't Idle import from .py files created after it was launched?

Question:

I can’t explain this phenomena, other than to assume that Idle somehow works off of a snapshot of the filesystem, taken at launch-time.

Repro steps:

  • create a myLib.py file with (e.g.):
#!/usr/bin/env python3

pre_launch_str = "Pre-launch!"
# post_launch_str = "Post-launch!"
  • launch Idle (from the containing folder)
  • from myLib import pre_launch_str works as expected: the string is imported/usable
  • Keep Idle running/open
  • [from another application/terminal] modify myLib.py to include a new object (e.g.) post_launch_str
  • from myLib import post_launch_str will throw an error:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'post_launch_str' from 'myLib' (/home/myUser/myLib.py)```

Anyone know what the cause of this is?

Linux (zsh) + Python 3.10 inthe example above, but I've noticed this long ago (~Python3.5 and on MacOS too)
Asked By: Adam Smooch

||

Answers:

This has nothing to do with IDLE. When you’ve already put a module into scope (regardless of which names you imported from it), Python will never reload that module. It assumes the module’s code has not changed and will use the in-memory version.

If you’re planning to modify the module live during development, you’ll need to use importlib to reload it. You need a reference to the module itself. If you imported the module name as import myLib, then myLib will do. Otherwise, take a class or function that you imported and get its __module__ (so pre_launch_str.__module__ in your example). Then take that and call reload on it.

from importlib import reload

reload(pre_launch_str.__module__)
Answered By: Silvio Mayolo

tl;dr: importlib.reload(myLib) does allow you to grab up-to-date content from myLib.py, but only if you imported the whole module with import myLib.

Based on Silvio’s answer, I did some playing around:

  • when using import X, it is possible to use reload(X) (note the lack of quotes around X)
  • when using from X import Y
    • reload(Y.__module__) will throw: TypeError: reload() argument must be a module
    • reload(X) will throw: NameError: name 'X' is not defined

As Silvio noted, class and function objects have the .__module__ attribute (while str, list, dict do not), but they return the name of the module, not the module itself.

Here be dragons!

It gets really weird if you mix the two import-types…

>>> from myLib import st
>>> st
'Pre!'
# Modify the value of `st` in myLib.py
>>> from importlib import reload
>>> reload(myLib)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'myLib' is not defined
>>> import myLib
>>> myLib.st    # it reused the `myLib` from memory
'Pre!'
>>> st
'Pre!'
>>> reload(myLib)
<module 'myLib' from '/home/user/myLib.py'>
>>> st    # still the originally-imported string
'Pre!'
>>> myLib.st
'Post!'
Answered By: Adam Smooch
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.