I will describe the basic process, which I learned from the presentation @jcollado linked to.
When Python starts, it looks at the path of the binary, and the prefixes thereof.
So let’s say your virtualenv is /home/blah/scratch
. The Python process knows it was executed from /home/blah/scratch/bin/python
(which is usually just a copy of your system python binary /usr/bin/python
) and it knows its own version X.Y
because it’s compiled into it. Then Python looks for lib/pythonX.Y/os.py
in this order:
/home/blah/scratch/bin/lib/pythonX.Y/os.py
/home/blah/scratch/lib/pythonX.Y/os.py <-- this file should exist
/home/blah/lib/pythonX.Y/os.py
/home/lib/pythonX.Y/os.py
/lib/pythonX.Y/os.py
It stops at /home/blah/scratch/lib/pythonX.Y/os.py
because it’s the first file that actually exists. If it didn’t, Python would keep looking. It then sets sys.prefix
based on this. It uses a similar process to set sys.exec_prefix
, and then sys.path
is constructed based on these.