can one python script run both with python 2.x and python 3.x

Many scripts can run on both 2.x and 3.x. (I've got a bunch I work on on a daily basis, and I've converted various open source libraries from 2.x-only to dual-version.)

A few things make it much easier:

  • Require 2.7, or at least 2.6+, for 2.x users. Otherwise, for example, you cannot raise and exceptions with parameters or catch them into variables, and other such severe limitations.
  • Require 3.3+, or at least 3.2+, for 3.x users. Most of the gratuitous incompatibilities (like the u prefix being taken away) were reversed in 3.2 or 3.3.
  • Use the six library.
  • Use __future__ statements.
  • Always be clear in your head about whether you mean bytes (always 8-bit), unicode (must encode if you want 8-bit), or str (whatever most of the stdlib APIs expect), and encode and decode as necessary.
  • Regularly run 2to3 on your code. (But don't blindly do everything it says. If, e.g., you're using d.keys() or map(f, l) because you don't care whether you get back a list or not, you'll get a warning, because 2to3 doesn't know you don't care.)

Alternatively, instead of trying to write code that runs on both, write code that runs on 2.x, but can be automatically transformed by 2to3 into running 3.x code, and make that part of your installation process (in setup.py, if sys.version_info >= (3, 0): do the 2to3 step).

From your edit, it sounds like you're mostly concerned with what to put in the #! line. For that:

/usr/bin/env python

This isn't guaranteed to work—but then env isn't guaranteed to work in the first-place… You can count on the fact that:

  • On just about any system where the platform/distro supplies only 2.x, python is Python 2.
  • On just about any system where the platform/distro supplies both, python is Python 2.
  • On just about any system where the platform/distro supplies only 3.x (which currently is very rare, but will presumably eventually be more common), python is Python 3.

However:

  • On a system where the platform supplies neither, if the admin only installed 3.x, it will likely (as of early 2013) not be available as python. There's not much you can do about this one.

If the last one is a serious problem, you can work around it by adding a launcher script, written in sh, that tries python and then tries python3 if that fails.

The nice way to do this is to specify the launcher script itself as the shebang interpreter in your Python script. Linux can handle this, but it's configurable, and at least some distros disable it by default—and most other *nix systems can't do it.

If that doesn't work, the next best option is to make the user run the launcher script—that is, tell them to do ./check.sh instead of ./check.py, and check.sh figures out the right Python interpreter and runs $python ./check.py for the user.

If you want to get really tricky, you could even embed the Python script as a heredoc inside the shell script, so you only need to distribute one file. They run ./check.sh, and it finds the right Python and runs it on the heredoc.