多行字符串的适当缩进?

函数中Python多行字符串的缩进方式是怎样的?

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

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

还是别的什么?

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

396099 次浏览

这取决于您希望文本如何显示。如果你想让它全部向左对齐,那么要么像第一个代码片段那样格式化它,要么遍历所有的行,向左修剪所有的空间。

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!

您可能想要与"""对齐

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

由于换行符和空格包含在字符串本身中,因此必须对其进行后处理。如果你不想这样做,而你有很多文本,你可能想把它们单独存储在一个文本文件中。如果一个文本文件不适合你的应用程序,而你不想进行后期处理,我可能会选择

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

如果你想对一个多行字符串进行后处理,去掉你不需要的部分,你应该考虑textwrap模块或PEP 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)

我在这里寻找一个简单的1-liner到文档字符串的移除/修正牙槽位,用于打印不要让它看起来不整洁,例如,通过使它在脚本中“悬挂在函数之外”。

这是我最后做的:

import string
def myfunction():


"""
line 1 of docstring
line 2 of docstring
line 3 of docstring"""


print str(string.replace(myfunction.__doc__,'\n\t','\n'))[1:]

显然,如果你使用空格缩进(例如4)而不是制表键,可以使用这样的方法:

print str(string.replace(myfunction.__doc__,'\n    ','\n'))[1:]

如果你想让你的文档字符串看起来像这样,你不需要删除第一个字符:

    """line 1 of docstring
line 2 of docstring
line 3 of docstring"""


print string.replace(myfunction.__doc__,'\n\t','\n')

更多的选择。在启用了pylab的Ipython中,dedent已经在名称空间中。我检查了一下,它来自matplotlib。或者可以导入:

from matplotlib.cbook import dedent

在文档中,它指出它比文本封装的等效程序要快,在我用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
"""

在这三个示例上使用matplotlib依赖项将得到相同的合理结果。textwrap dedent函数将在第一个示例中有一个前导空行。

明显的缺点是textwrap在标准库中,而matplotlib是外部模块。

这里有一些权衡……在定义字符串的地方,dedent函数使代码更具可读性,但需要稍后处理以获得可用格式的字符串。在文档字符串中,很明显应该使用正确的缩进,因为大多数使用文档字符串都会执行所需的处理。

当我需要一个非长字符串在我的代码中,我发现以下承认丑陋的代码,我让长字符串退出封闭缩进。“美丽总比丑陋好”这句话绝对不合适,但有人可能会说,它比抑扬抑扬的说法更简单、更明确。

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()

一个选项似乎在其他答案中遗漏了(只在naxa的评论中提到过):

def foo():
string = ("line one\n"          # Add \n in the string
"line two"  "\n"      # Add "\n" after the string
"line three\n")

这将允许适当的对齐,隐式地连接行,并仍然保持行移位,对我来说,这是为什么我想使用多行字符串的原因之一。

它不需要任何后处理,但是您需要手动在希望该行结束的任何给定位置添加\n。可以内联,也可以作为单独的字符串。后者更容易复制粘贴进来。

如果你想要一个快速简单的解决方案,并且避免输入换行符,你可以选择一个列表来代替,例如:

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

我更喜欢

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

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

我的观点是,转义行尾以获得缩进

def foo():
return "{}\n"\
"freq: {}\n"\
"temp: {}\n".format( time, freq, temp )

对于字符串,可以直接处理字符串。对于文档字符串,您需要在之后处理函数。这里有一个解决方案,这两个仍然是可读的。

class Lstrip(object):
def __rsub__(self, other):
import re
return re.sub('^\n', '', re.sub('\n$', '', re.sub('\n\s+', '\n', other)))


msg = '''
Lorem ipsum dolor sit amet, consectetur adipiscing 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 ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
''' - Lstrip()


print msg


def lstrip_docstring(func):
func.__doc__ = func.__doc__ - Lstrip()
return func


@lstrip_docstring
def foo():
'''
Lorem ipsum dolor sit amet, consectetur adipiscing 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 ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
'''
pass




print foo.__doc__

像这样使用inspect.cleandoc:

import inspect


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

相对压痕将按预期保持。正如下面的评论,如果你想保持前面的空行,使用textwrap.dedent。但是,这也保留了第一个换行符。

将代码的逻辑块缩进到相关的上下文中以澄清结构是一种很好的实践。例如,多行字符串属于变量string

第一个选项是好的-包括缩进。 它是python风格的-提供了代码的可读性

正确显示:

print string.lstrip()