Python 2 vs. 3, Shebangs, and Launchers
04 May 2017If you run an arbitrary Python program, how does your system decide whether it’s Python 2 or 3?
Linux and OS X
On POSIX systems (Linux and OS X), a Python script starts with a shebang that says whether it’s Python 2 or 3.
#!/usr/bin/python
print "Hello from Python 2!"
#!/usr/bin/python3
print("Hello from Python 3!")
Python 2 scripts will sometimes use /usr/bin/python2
instead of
/usr/bin/python
. The official commentary on this is PEP
394, which recommends only using
python
for code that’s source-compatible with both Python 2 and Python 3.
However, most Python 2 code that I’ve seen doesn’t follow that recommendation,
either because it predates PEP 394 or because of inertia.
A common variation is to run env
instead of invoking the Python binary
directly:
#!/usr/bin/env python3
print("Hello from Python 3!")
According to its manpage, the env
command
is used to “run a program in a modified environment.” In practice, though, it’s
most commonly used in shebangs, as a way of saying, “Run the following command,
wherever it resides in the
PATH, instead of making me
hard-code its location.” For Python, this is useful when using
pyenv or virtual environments, since it will
find pyenv’s or your virtualenv’s Python and run the Python code through that
instead of using the system Python.
Windows
On Windows, you can only register a single executable for a file suffix, but
Python provides a launcher called py.exe
that’s smart enough to look at a
.py
file’s shebang and decide which version of Python to launch. The Python
launcher is typically automatically installed along with Python and is
typically installed to c:\windows\py.exe
. It’s documented in more detail in
PEP 397.
It’s possible that Windows file associations might get changed, such that
double-clicking on a .py
file no longer runs it through the launcher. To
troubleshoot:
- Run
regedit.exe
. (Windows’ “default programs” control panel may work too, but it doesn’t always offer enough control, and it’s changed a lot in different Windows versions, making it harder to write instructions for.) - Go to
HKEY_CLASSES_ROOT\.py
. TheDefault
value should readPython.File
. - Go to
HKEY_CLASSES_ROOT\Python.File\shell\open\command
. TheDefault
value should read"C:\WINDOWS\py.exe" "%L" %*
.
As of Python 3.5, the Python launcher supports virtual environments (see PEP
486), so that you can open a
Windows command prompt or PowerShell prompt, activate a virtualenv, then run
my_script.py
at the C: prompt and have it run within your virtualenv.
Unfortunately, I haven’t had much success using this:
- The Windows launcher only invokes a virtualenv if no explicit version is
given, so
you need a shebang like
#!/usr/bin/env python
. - On Linux,
python
usually means Python 2, so Linux-compatible Python 3 code typically needs a shebang like#!/usr/bin/env python3
.
The workaround is to run python
yourself from the command line, instead of
relying on the launcher. In other words, instead of running my_script.py
at
the C: prompt, run python my_script.py
. This explicitly invokes the
virtualenv python
from of your PATH and tells it to run your script itself,
regardless of Windows’ file associations.