A question related to the PYTHONPATH
adrien oyono
adrienoyono at gmail.com
Sun Mar 25 08:40:04 EDT 2018
Hello everyone,
This is my first email to the python list, I'll try my best to do it well.
TL;DR
I have recently read the documentation about how imports work on python,
and I was wondering why, when you execute a python file, the current
directory is not added by default to the PYTHONPATH ?
Extended:
Let's assume we have this directory structure for a python package:
$ tree A
A
├── B1
│ ├── b1.py
│ ├── C1
│ │ ├── c1_1.py
│ │ ├── c1.py
│ │ └── __init__.py
│ └── __init__.py
├── B2
│ ├── b2.py
│ ├── C2
│ │ ├── c2.py
│ │ └── __init__.py
│ └── __init__.py
├── __init__.py
└── toto.py
4 directories, 11 files
with the file A/B2/C2/c2.py content being:
import sys
print(sys.path)
import A
from A.B2.b2 import PLOP
from A.B1.C1.c1 import TOTO
print(TOTO)
If I do, from the top level directory containing the package A:
$ python A/B2/C2/c2.py
I get an :
['/tmp/A/B2/C2', '/usr/lib/python2.7',
'/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/home/cris/.local/lib/python2.7/site-packages',
'/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-
packages/gtk-2.0']
Traceback (most recent call last):
File "A/B2/C2/c2.py", line 9, in <module>
import A
ImportError: No module named A
Which is normal according to the documentation of Python 2
(https://docs.python.org/2/tutorial/modules.html#the-module-search-path):
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
> <https://docs.python.org/2/library/sys.html#sys.path>. sys.path
> <https://docs.python.org/2/library/sys.html#sys.path> is initialized from
> these locations:
>
> - the directory containing the input script (or the current directory).
> - PYTHONPATH
> <https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH> (a
> list of directory names, with the same syntax as the shell variable
> PATH).
> - the installation-dependent default.
>
> After initialization, Python programs can modify sys.path
> <https://docs.python.org/2/library/sys.html#sys.path>. The directory
> containing the script being run is placed at the beginning of the search
> path, ahead of the standard library path. This means that scripts in that
> directory will be loaded instead of modules of the same name in the library
> directory. This is an error unless the replacement is intended. See section Standard
> Modules
> <https://docs.python.org/2/tutorial/modules.html#tut-standardmodules> for
> more information.
>
Meanwhile when I do:
$ python -m A.B2.C2.c2
I get the script running correctly:
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/home/cris/.local/lib/python2.7/site-packages',
'/usr/local/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages/PILcompat',
'/usr/lib/python2.7/dist-packages/gtk-2.0']
42
An empty string is now pre-pended to the value of sys.path, which means, if
I correctly interpret the documentation of Python 3, that the current
directory is added to the PYTHONPATH (https://docs.python.org/3/
reference/import.html#path-entry-finders):
The current working directory – denoted by an empty string – is handled
> slightly differently from other entries on sys.path
> <https://docs.python.org/3/library/sys.html#sys.path>. First, if the
> current working directory is found to not exist, no value is stored in
> sys.path_importer_cache
> <https://docs.python.org/3/library/sys.html#sys.path_importer_cache>.
> Second, the value for the current working directory is looked up fresh for
> each module lookup. Third, the path used for sys.path_importer_cache
> <https://docs.python.org/3/library/sys.html#sys.path_importer_cache> and
> returned by importlib.machinery.PathFinder.find_spec()
> <https://docs.python.org/3/library/importlib.html#importlib.machinery.PathFinder.find_spec>
> will be the actual current working directory and not the empty string.
>
What I am interested in is what is the reason of this difference ?
P.S.:
- My english may suck a bit, please blame it on me being a French native
speaker
- Sorry if the colours hurt 😅
*Adrien OYONO*
More information about the Python-list
mailing list