Python 2 vs. 3, Shebangs, and Launchers

If 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:

  1. 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.)
  2. Go to HKEY_CLASSES_ROOT\.py. The Default value should read Python.File.
  3. Go to HKEY_CLASSES_ROOT\Python.File\shell\open\command. The Default 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 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.