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