Python Idioms: Multiline Strings

I rarely see Multiline strings used in Python code outside of docstrings, but they can be very useful, especially when you need to create a very specifically structured string, like a code snippet, help section to print to the screen or ASCII art for a snake. The problem is that it’s just ugly, because indenting the strings actually inserts the indentation into the string. So you have to do this:

def create_snippet():
    code_snippet = """\
int main(int argc, char* argv[]) {
    return 0;
}"""
    do_something(code_snippet)

This is just unbearable, unreadable Python. When working on pydocstyle, I had to test a Python code parser. I wanted to find a way to feed it a tiny Python source code snippet in each test. After some tinkering, I found a really handy idiom that makes multiline strings in Python look nice:

def create_snippet():
    code_snippet = textwrap.dedent("""\
        int main(int argc, char* argv[]) {
            return 0;
        }
    """)
    do_something(code_snippet)

The secret sauce to this is textwrap.dedent. The textwrap module is in the standard library, so there’s really no excuse not to use it. What it does is it “removes any common leading whitespace from every line in text”. With dedent, we can indent the whole multiline string according to the current scope, so that it looks like a Pythonic code block.

To undestand how dedent works, here’s the same snippet as above, with marked whitespaces for the multiline string. The - whitespaces will be removed and the + whitespaces will not:

def create_snippet():
    code_snippet = textwrap.dedent("""\
--------int main(int argc, char* argv[]) {
--------++++return 0;
--------}
    """)  # This line is only whitespace, so `dedent` ignores it.
    do_something(code_snippet)

The first line can cause us some trouble here, because although it will not mess with the indentation, it will insert a newline at the beginning of our string. So we use backslash-linebreak immediately after opening the string, which lets us do a line break in the source code, but not in the string itself. Then, the first line is indented as well, which lets dedent do the rest of the heavy lifting. I like to indent the multiline string one indentation further than the current scope, to make it a distinct block.

Discuss this post at /r/Python, Lobsters, or the comment section below.
Follow me on Twitter and Facebook
Thanks to Hannan Aharonov, Yonatan Nakar, Ram Rachum, Shachar Ohana and Shachar Nudler for reading drafts of this.

Similar Posts