函数中 Python 多行字符串的正确缩进是什么?
def method():
string = """line one
line two
line three"""
或者
def method():
string = """line one
line two
line three"""
或者是其他东西?
在第一个示例中,将字符串挂在函数之外看起来有点奇怪。
method.__doc__
不会像任何其他 str
文字那样被 Python 本身修改。
您可能想与 """
排队
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)
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!
textwrap.dedent()
调用的结果是一个常量值,就像它的输入参数一样。
def foo: return foo.x
然后下一行 foo.x = textwrap.dedent("bar")
。
像这样使用 inspect.cleandoc
:
import inspect
def method():
string = inspect.cleandoc("""
line one
line two
line three""")
将按预期保持相对缩进。如下面的 commented,如果要保留前面的空行,请使用 textwrap.dedent
。但是,这也保留了第一个换行符。
注意:最好在相关上下文下缩进逻辑代码块以阐明结构。例如属于变量字符串的多行字符串。
inspect.cleandoc
从 Python 2.6 就已经存在,即 2008..?绝对是最干净的答案,特别是因为它不使用悬挂缩进样式,这只会浪费不必要的空间
其他答案中似乎缺少的一个选项(仅在 naxa 的评论中深入提及)如下:
def foo():
string = ("line one\n" # Add \n in the string
"line two" "\n" # Add "\n" after the string
"line three\n")
这将允许正确对齐,隐式连接线,并且仍然保持线移位,对我来说,这是我无论如何都想使用多行字符串的原因之一。
它不需要任何后处理,但您需要在您希望该行结束的任何给定位置手动添加 \n
。内联或作为单独的字符串之后。后者更容易复制粘贴。
还有一些选择。在启用了 pylab 的 Ipython 中,dedent 已经在命名空间中。我查了一下,它来自matplotlib。或者可以通过以下方式导入:
from matplotlib.cbook import dedent
在文档中,它指出它比等效的 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
"""
在这三个示例上使用 matplotlib dedent 将给出相同的合理结果。 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()
如果您想要一个快速简便的解决方案并避免输入换行符,您可以选择一个列表,例如:
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 )
我来这里是为了寻找一个简单的 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)而不是 tab 键缩进,请改用以下内容:
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')
对于字符串,您可以在处理字符串之后。对于文档字符串,您需要改为在处理函数之后。这是一个仍然可读的解决方案。
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
——以正确的方式做到这一点。
第一个选项是好的选项 - 包括缩进。它采用 python 风格 - 为代码提供可读性。
要正确显示它:
print string.lstrip()
这取决于您希望文本如何显示。如果您希望所有内容都左对齐,则可以将其格式化为第一个片段中的格式,或者遍历左修剪所有空间的行。
trim()
函数在标准库中实现为inspect.cleandoc
。string
更改为text
或其他任何长度,那么您现在需要更新缩进实际上是多行字符串的每一行,只是为了让它与"""
正确匹配。缩进策略不应该使未来的重构/维护复杂化,这是 PEP 真正失败的地方之一