7

Python import shadowing seems to be different between version 3.4.6 and 3.5.2 :

$ cat time.py
from time import time
$ pyenv global 3.4.6
$ python -V
Python 3.4.6
$ python time.py 
Traceback (most recent call last):
  File "time.py", line 1, in <module>
    from time import time
  File "/home/vagrant/tmp/time.py", line 1, in <module>
    from time import time
ImportError: cannot import name 'time'
$ pyenv global 3.5.2 
$ python -V
Python 3.5.2
$ python time.py
$ echo no error
no error

Question 1: Why is... those things ?

Question 2: Is it there something in a changelog about that ? I can't find anything...

Luc PHAN
  • 316
  • 2
  • 13

1 Answers1

7

The documentation states that

When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path.

(emphasis mine)

time wasn't a built-in module module in Python 3.4, but that changed in Python 3.5:

me@temp:~$ python3.4 -c 'import sys; print("time" in sys.builtin_module_names)'
False
me@temp:~$ python3.5 -c 'import sys; print("time" in sys.builtin_module_names)'
True

You can see the patch that introduced the change here (related to issue 5309). Considering that the changelog mentions the issue 5309, but doesn't say anything re. the time module, it's safe to say that the change was a side-effect and is an implementation detail of CPython.

Since time isn't a built-in module in CPython 3.4, and the first directory in sys.path is the current script directory, from time import time attempts to import the time attribute from your time.py file, but fails and throws the ImportError.

In CPython 3.5 time is a built-in module. As per the quote above, running from time import time successfully imports the built-in module, without searching for modules on sys.path.

Both CPython versions will raise the same error if you shadow a non-builtin module from the standard library, such as inspect:

me@temp:~$ cat inspect.py 
from inspect import signature
me@temp:~$ python3.4 -c 'import inspect'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/me/inspect.py", line 1, in <module>
    from inspect import signature
ImportError: cannot import name 'signature'
me@temp:~$ python3.5 -c 'import inspect'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/me/inspect.py", line 1, in <module>
    from inspect import signature
ImportError: cannot import name 'signature'
vaultah
  • 44,105
  • 12
  • 114
  • 143
  • If the import machinery is willing to special-case names like this, why not put *every* standard library module into an exceptions list, so that [the standard library doesn't accidentally try to import the user's code instead of its own](https://stackoverflow.com/a/52271581/523612)? – Karl Knechtel Jan 10 '23 at 03:34