Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python import shadowing different between 3.4.6 and 3.5.2

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...

like image 935
Nielas Aran Avatar asked Jul 19 '17 19:07

Nielas Aran


People also ask

What is import * in Python?

In Python, you use the import keyword to make code in one module available in another. Imports in Python are important for structuring your code effectively. Using imports properly will make you more productive, allowing you to reuse code while keeping your projects maintainable.

Does Python cache imports?

Python caches all imported modules This all happened because Python caches modules. In Python, every module that is imported is stored in a dictionary called sys.

Why can't Python find my import?

This is caused by the fact that the version of Python you're running your script with is not configured to search for modules where you've installed them. This happens when you use the wrong installation of pip to install packages.

What are the different methods of importing the Python module?

So there's four different ways to import: Import the whole module using its original name: pycon import random. Import specific things from the module: pycon from random import choice, randint. Import the whole module and rename it, usually using a shorter variable name: pycon import pandas as pd.


Video Answer


1 Answers

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'
like image 180
vaultah Avatar answered Sep 18 '22 15:09

vaultah