多行字符串的正确缩进?

618 投票
12 回答
441309 浏览
提问于 2025-04-15 20:46

在Python中,函数里的多行字符串应该怎么缩进呢?

    def method():
        string = """line one
line two
line three"""

或者

    def method():
        string = """line one
        line two
        line three"""

或者其他什么方式呢?

在第一个例子中,字符串悬在函数外面,看起来有点奇怪。

12 个回答

176

使用 inspect.cleandoc()

import inspect

def method():
    string = inspect.cleandoc("""
        line one
        line two
        line three""")

inspect.cleandoc()textwrap.dedent() 的作用:

  • 计算最不缩进的非空行前面的空格数
  • 从每一行非空行中去掉这个空格数

inspect.cleandoc() 还额外做了什么:

  • 去掉结果开头和结尾的 \n(换行符)

注意:在相关的上下文中缩进代码块是个好习惯,这样可以更清晰地表达结构。例如,属于变量 string 的多行字符串。

385

textwrap.dedent 这个函数可以让你在源代码中使用正确的缩进,然后在使用之前把这些缩进去掉。

不过,有人提到,这样做会多调用一个函数,所以在决定把这些文本放在哪里时,要考虑到这一点。

import textwrap

def frobnicate(param):
    """ Frobnicate the scrognate param.

        The Weebly-Ruckford algorithm is employed to frobnicate
        the scrognate to within an inch of its life.
        """
    prepare_the_comfy_chair(param)
    log_message = textwrap.dedent("""\
            Prepare to frobnicate:
            Here it comes...
                Any moment now.
            And: Frobnicate!""")
    weebly(param, log_message)
    ruckford(param)

日志信息中的结尾 \ 是为了确保换行符不会出现在文本中;这样,文本就不会以空行开始,而是直接从下一行开始。

使用 textwrap.dedent 后返回的结果是输入字符串中每一行的共同前导空白缩进都被去掉了。所以上面的 log_message 的值将会是:

Prepare to frobnicate:
Here it comes...
    Any moment now.
And: Frobnicate!
536

你可能想要对齐到 """ 的位置。

def foo():
    string = """line one
             line two
             line three"""

因为字符串里面包含了换行和空格,所以你需要进行后处理。如果你不想这样做,而且文本量很大,可能更好把它单独存储在一个文本文件里。如果文本文件不适合你的应用,而且你也不想后处理,那我建议你可以使用

def foo():
    string = ("this is an "
              "implicitly joined "
              "string")

如果你想对多行字符串进行后处理,去掉不需要的部分,可以考虑使用 textwrap 模块,或者参考 PEP 257 中介绍的处理文档字符串的方法:

def trim(docstring):
    import sys
    if not docstring:
        return ''
    # Convert tabs to spaces (following the normal Python rules)
    # and split into a list of lines:
    lines = docstring.expandtabs().splitlines()
    # Determine minimum indentation (first line doesn't count):
    indent = sys.maxint
    for line in lines[1:]:
        stripped = line.lstrip()
        if stripped:
            indent = min(indent, len(line) - len(stripped))
    # Remove indentation (first line is special):
    trimmed = [lines[0].strip()]
    if indent < sys.maxint:
        for line in lines[1:]:
            trimmed.append(line[indent:].rstrip())
    # Strip off trailing and leading blank lines:
    while trimmed and not trimmed[-1]:
        trimmed.pop()
    while trimmed and not trimmed[0]:
        trimmed.pop(0)
    # Return a single string:
    return '\n'.join(trimmed)

撰写回答