It's actually moderately complicated. The story starts in the C code, which is what looks at $PYTHONPATH
initially, but continues from there.
In all cases, but especially if Python is being invoked as an embedded interpreter (including "framework" stuff on MacOS X), at least a little bit of "magic" is done to build up an internal path string. (When embedded, whatever is running the embedded Python interpreter can call Py_SetPath
, otherwise python tries to figure out how it was invoked, then adjust and add lib/pythonX.Y
where X and Y are the major and minor version numbers.) This internal path construction is done so that Python can find its own standard modules, things like collections
and os
and sys
. $PYTHONHOME
can also affect this process. In general, though, the environment $PYTHONPATH
variable—unless suppressed via -E
—winds up in front of the semi-magic default path.
The whole schmear is used to set the initial value of sys.path
. But then as soon as Python starts up, it loads site.py
(unless suppressed via -S
). This modifies sys.path
rather extensively—generally preserving things imported from $PYTHONPATH
, in their original order, but shoving a lot of stuff (like system eggs) in front.1 Moreover, one of the things it does is load—if it exists—a per-user file $HOME/.local/lib/pythonX.Y/sitepackages/usercustomize.py
, and that can do anything, there are no guarantees:
$ cat usercustomize.py
print 'hello from usercustomize'
$ python
hello from usercustomize
Python 2.7.5 (default, Jun 15 2013, 11:50:00)
[GCC 4.2.1 20070831 patched [FreeBSD]] on freebsd9
Type "help", "copyright", "credits" or "license" for more information.
>>>
If I were to put:
import random, sys
random.shuffle(sys.path)
this would scramble sys.path
, putting $PYTHONPATH
elements in random order. Arguably this is a case of "ok, you shot yourself in the foot, that's your problem". :-) But anything I import can similarly mess with sys.path
, so it's possible for something other than my own usercustomize.py
to ruin the desired effect (of $PYTHONPATH
ordering being preserved).
1 Footnote (late edit): actually the eggs come from site-packages/site.py
, which does its own os.getenv("PYTHONPATH")
. So it's even messier, in a way. The general principle applies though: standard code should preserve path order, but you can break it.