Python多行字符串的正确缩进

ens*_*are 430 python string

函数中Python多行字符串的正确缩进是什么?

    def method():
        string = """line one
line two
line three"""
Run Code Online (Sandbox Code Playgroud)

要么

    def method():
        string = """line one
        line two
        line three"""
Run Code Online (Sandbox Code Playgroud)

或者是其他东西?

在第一个例子中将字符串悬挂在函数外部看起来有点奇怪.

Mik*_*ham 439

你可能想要排队 """

def foo():
    string = """line one
             line two
             line three"""
Run Code Online (Sandbox Code Playgroud)

由于换行符和空格都包含在字符串本身中,因此您必须对其进行后处理.如果您不想这样做并且您有大量文本,则可能需要将其单独存储在文本文件中.如果文本文件不适合您的应用程序,并且您不想进行后期处理,我可能会选择

def foo():
    string = ("this is an "
              "implicitly joined "
              "string")
Run Code Online (Sandbox Code Playgroud)

如果要对多行字符串进行后处理以修剪掉不需要的部分,则应考虑textwrapPEP 257中提供的后处理文档字符串的模块或技术:

def trim(docstring):
    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)
Run Code Online (Sandbox Code Playgroud)

  • 如在PEP257中指定的修剪`()`函数在标准库作为[`inspect.cleandoc`](https://docs.python.org/2/library/inspect.html#inspect.cleandoc)来实现. (16认同)
  • 这是线条延续的"悬挂缩进"风格.在PEP8中规定了函数定义和long if语句之类的用途,尽管多线字符串没有提及.就个人而言,这是一个我拒绝遵循PEP8的地方(而是使用4空格缩进),因为我非常不喜欢悬挂缩进,这让我模糊了程序的正确结构. (10认同)
  • *具有自动字符串连接的第二种形式不包括换行符*这是一个功能. (5认同)
  • @buffer,在官方教程的3.1.2中("两个字符串文字彼此相邻,自动连接......")和语言参考. (2认同)
  • @bobince关于拒绝"悬挂缩进"的评论+1 ...特别是因为如果你将变量名称从`string`更改为`text`或任何不同长度的东西,那么你现在需要更新缩进*字面上多行字符串的每一行*只是为了让它与`"""正确匹配.缩进策略不应该使未来的重构/维护变得复杂,而且它是PEP真正失败的地方之一 (2认同)

big*_*ose 239

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)
Run Code Online (Sandbox Code Playgroud)

\日志消息文字中的尾随是为了确保换行符不在文字中; 这样,文字不会以空行开头,而是从下一个完整行开始.

返回值textwrap.dedent是输入字符串,在字符串的每一行上删除所有常见的前导空格缩进.所以上面的log_message值将是:

Prepare to frobnicate:
Here it comes...
    Any moment now.
And: Frobnicate!
Run Code Online (Sandbox Code Playgroud)

  • @jtmoulia:比灾难更好的描述是"低效"的,因为`textwrap.dedent()`调用的结果是一个常量值,就像它的输入参数一样. (9认同)
  • @haridsv 为什么这会是一场灾难? (3认同)
  • 虽然这是一个合理的解决方案并且很高兴知道,但在一个经常调用的函数中做这样的事情可能会被证明是一场灾难。 (2认同)
  • @haridsv灾难/低效率的根源是*定义*常量字符串*内部*一个经常调用的函数。可以将每个呼叫常量定义用于每个呼叫查找。这样,* dedent *预处理将*仅运行*。一个相关的问题可能是http://stackoverflow.com/q/15495376/611007。它列出了一些想法,以避免为每个调用定义常量。尽管替代方案似乎需要查找。尽管如此,尝试了各种寻找合适的存储位置的方法。例如:`def foo:return foo.x`,然后下一行`foo.x = textwrap.dedent(“ bar”)`。 (2认同)

wih*_*lke 32

使用inspect.cleandoc如下:

def method():
    string = inspect.cleandoc("""
        line one
        line two
        line three""")
Run Code Online (Sandbox Code Playgroud)

相对缩进将按预期保持.

注意:最好在其相关上下文中缩进代码的逻辑块以阐明结构.例如,属于变量的多行字符串textwrap.dedent.

  • 如此困惑为什么直到现在才没有这个答案,自[Python 2.6](https://docs.python.org/2/library/inspect.html#inspect.cleandoc)以来,一直存在`inspect.cleandoc`。是[2008](https://www.python.org/download/releases/2.6/)..?绝对是最干净的答案,尤其是因为它不使用悬挂式缩进样式,这只会浪费不必要的空间 (2认同)

hol*_*roy 22

其他答案中似乎缺少的一个选项(仅在naxa的评论中深入提及)如下:

def foo():
    string = ("line one\n"          # Add \n in the string
              "line two"  "\n"      # Add "\n" after the string
              "line three\n")
Run Code Online (Sandbox Code Playgroud)

这将允许正确对齐,隐含地连接线,并仍然保持线移位,对我来说,这是我想要使用多线字符串的原因之一.

它不需要任何后期处理,但您需要\n在任何给定位置手动添加您希望该行结束的位置.内联或后面的单独字符串.后者更容易复制粘贴.

  • 请注意,这是隐式连接字符串的示例,而不是多行字符串。 (2认同)
  • @trk,它是多行的,因为字符串包含换行符(也称为多行),但是它使用连接来规避OP的格式问题。 (2认同)

Joo*_*oop 17

还有一些选择.在启用了pylab的Ipython中,dedent已经在命名空间中.我查了一下,它来自matplotlib.或者它可以导入:

from matplotlib.cbook import dedent
Run Code Online (Sandbox Code Playgroud)

在文档中它声明它比textwrap等效的快,并且在我的ipython测试中,它的平均速度确实比我的快速测试快3倍.它还有一个好处,它丢弃任何前导空行,这使您可以灵活地构建字符串:

"""
line 1 of string
line 2 of string
"""

"""\
line 1 of string
line 2 of string
"""

"""line 1 of string
line 2 of string
"""
Run Code Online (Sandbox Code Playgroud)

在这三个例子中使用matplotlib dedent将给出相同的合理结果.textwrap dedent函数将在第一个示例中有一个前导空白行.

显而易见的缺点是textwrap在标准库中,而matplotlib是外部模块.

这里有一些权衡... dedent函数使得代码在字符串定义时更具可读性,但稍后需要处理才能使字符串成为可用格式.在文档字符串中,显然您应该使用正确的缩进,因为docstring的大多数用法都将执行所需的处理.

当我在我的代码中需要一个非长字符串时,我发现以下公认的丑陋代码,其中我让长字符串从封闭缩进中删除.绝对失败的是"美丽胜过丑陋."但是有人可能会认为它比狡猾的选择更简单,更明确.

def example():
    long_string = '''\
Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip.\
'''
    return long_string

print example()
Run Code Online (Sandbox Code Playgroud)


ste*_*ert 5

如果您想要一个快速简便的解决方案并且不用输入换行符,您可以选择列表,例如:

def func(*args, **kwargs):
    string = '\n'.join([
        'first line of very long string and',
        'second line of the same long thing and',
        'third line of ...',
        'and so on...',
        ])
    print(string)
    return
Run Code Online (Sandbox Code Playgroud)

  • 虽然这不是最好的方法,但我时常使用它。如果您“确实”使用它,则应该使用元组而不是列表,因为它在连接之前不会被修改。 (3认同)

lk_*_*_vc 5

我更喜欢

    def method():
        string = \
"""\
line one
line two
line three\
"""
Run Code Online (Sandbox Code Playgroud)

或者

    def method():
        string = """\
line one
line two
line three\
"""
Run Code Online (Sandbox Code Playgroud)

  • 这并不能回答问题,因为问题明确指出缩进(在函数内)很重要。 (3认同)