We're back after a server migration that caused effbot.org to fall over a bit harder than expected. Expect some glitches.

Why can't raw strings (r-strings) end with a backslash?

Raw string literals are parsed in exactly the same way as ordinary string literals; it’s just the conversion from string literal to string object that’s different. This means that all string literals must end with an even number of backslashes; otherwise, the unpaired backslash at the end escapes the closing quote character, leaving an unterminated string.

Raw strings were designed to ease creating input for processors, such as regular expression engines, that want to do their own backslash escape processing. Such processors consider an unmatched trailing backslash to be an error anyway, so raw strings disallow that. In return, they allow you to pass on the string quote character by escaping it with a backslash. These rules work well when r-strings are used for their intended purpose.

If you’re trying to use raw strings to build Windows path names, note that all Windows system calls accept forward slashes too:

f = open("/mydir/file.txt") # works fine!

The exception is commands passed to the Windows command interpreter (command.com or cmd.exe). The easiest way to handle that is to run the filename through os.path.normpath before passing it to the command interpreter:

arg = os.path.normpath("/this/is/my/dos/dir/")
os.system("myapp " + arg)

Note that getting the slashes right before you call os.system still won’t help you with spaces and other special characters. To write robust code, you can use the subprocess.list2cmdline helper function. It takes a list of arguments, and turns them into a properly quoted command line:

import os
import subprocess

def mysystem(command, *files):
    files = map(os.path.normpath, files)
    files = subprocess.list2cmdline(files)
    return os.system(command + " " + files)

mysystem("more", "/program files/subversion/readme.txt")

But then you might as well use subprocess.call and the shell option, of course.

But back to the raw strings; if you really want to add a backslash to the end of a raw string, you can work around the parser limitation by doing:

arg = r"\this\is\my\dos\dir" "\\"

or

arg = r"\this\is\my\dos\dir\ "[:-1]