多行字符串的缩进是否正确?
- 2025-03-04 08:24:00
- admin 原创
- 61
问题描述:
函数内 Python 多行字符串的正确缩进是什么?
def method():
string = """line one
line two
line three"""
或者
def method():
string = """line one
line two
line three"""
或者其他的?
在第一个例子中,字符串悬挂在函数外面看起来有点奇怪。
解决方案 1:
你可能想和"""
def foo():
string = """line one
line two
line three"""
由于换行符和空格包含在字符串本身中,因此您必须对其进行后处理。如果您不想这样做,并且您有大量文本,则可能需要将其单独存储在文本文件中。如果文本文件不适合您的应用程序并且您不想进行后处理,我可能会选择
def foo():
string = ("this is an "
"implicitly joined "
"string")
如果您想要对多行字符串进行后处理以删除不需要的部分,则应该考虑使用PEP 257textwrap
中介绍的后处理文档字符串的模块或技术:
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 '
'.join(trimmed)
解决方案 2:
该功能允许人们从源中的正确缩进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("""\n 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!
解决方案 3:
使用inspect.cleandoc()
:
import inspect
def method():
string = inspect.cleandoc("""
line one
line two
line three""")
inspect.cleandoc()
和均textwrap.dedent()
:
计算缩进最少的非空行的前导空格数
从每个非空行中删除该数量的空格
另外还有什么inspect.cleandoc()
:
`
`从结果中删除前导和尾随
注意:在相关上下文中缩进逻辑代码块以明确结构是一种很好的做法。例如属于变量的多行字符串
string
。
解决方案 4:
其他答案中似乎缺少一个选项(仅在 naxa 的评论中深处提到),如下所示:
def foo():
string = ("line one
" # Add
in the string
"line two" "
" # Add "
" after the string
"line three
")
这将允许正确的对齐,隐式地连接行,并且仍然保持行移位,对我来说,这也是我想要使用多行字符串的原因之一。
它不需要任何后处理,但您需要`
`在希望行结束的任何给定位置手动添加。可以内联或作为单独的字符串。后者更容易复制粘贴。
解决方案 5:
更多选项。在启用 pylab 的 Ipython 中,dedent 已位于命名空间中。我检查了一下,它来自 matplotlib。或者可以使用以下命令导入:
from matplotlib.cbook import dedent
在文档中,它指出它比 textwrap 等效方法更快,在我的 ipython 测试中,它确实平均快 3 倍。它还有一个好处,就是它会丢弃任何前导空行,这允许您灵活地构造字符串:
"""
line 1 of string
line 2 of string
"""
"""\nline 1 of string
line 2 of string
"""
"""line 1 of string
line 2 of string
"""
在这三个示例中使用 matplotlib dedent 将得到相同的合理结果。textwrap dedent 函数将在第 1 个示例中以空白行开头。
明显的缺点是 textwrap 在标准库中,而 matplotlib 是外部模块。
这里有一些权衡... dedent 函数使你的代码更具可读性,因为字符串被定义,但需要稍后处理才能获得可用格式的字符串。在文档字符串中,显然你应该使用正确的缩进,因为大多数文档字符串的使用都会进行所需的处理。
当我需要在代码中使用非长字符串时,我发现以下代码确实很丑陋,我让长字符串脱离了封闭的缩进。这显然不符合“美丽胜过丑陋”的原则,但有人可能会说,它比去缩进的替代方案更简单、更明确。
def example():
long_string = '''\nLorem 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.\n'''
return long_string
print example()
解决方案 6:
如果您想要一个快速简便的解决方案并避免输入换行符,您可以选择列表,例如:
def func(*args, **kwargs):
string = '
'.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
解决方案 7:
我更喜欢
def method():
string = \n"""\nline one
line two
line three\n"""
或者
def method():
string = """\nline one
line two
line three\n"""
解决方案 8:
我的意见是,跳过行尾以获得缩进:
def foo():
return "{}
"\n "freq: {}
"\n "temp: {}
".format( time, freq, temp )
解决方案 9:
我来这里寻找一个简单的单行程序来删除/更正打印文档字符串的标识级别,而不会使其看起来不整洁,例如通过使其在脚本中“挂在函数之外”。
以下是我最终做的事情:
import string
def myfunction():
"""
line 1 of docstring
line 2 of docstring
line 3 of docstring"""
print str(string.replace(myfunction.__doc__,'
','
'))[1:]
显然,如果您使用空格(例如 4)而不是 Tab 键缩进,请改用以下命令:
print str(string.replace(myfunction.__doc__,'
','
'))[1:]
如果您希望文档字符串看起来像这样,则不需要删除第一个字符:
"""line 1 of docstring
line 2 of docstring
line 3 of docstring"""
print string.replace(myfunction.__doc__,'
','
')
解决方案 10:
对于字符串,您可以直接处理字符串。对于文档字符串,您需要处理函数。这里有一个仍然可读的解决方案。
class Lstrip(object):
def __rsub__(self, other):
import re
return re.sub('^
', '', re.sub('
$', '', re.sub('
s+', '
', 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__
解决方案 11:
第一个选项比较好 - 包含缩进。它采用 Python 风格 - 为代码提供了可读性。
要正确显示它:
print string.lstrip()
解决方案 12:
感谢您的帮助,我已经稍微改进了一下课程:
import inspect
import re
class Lstrip:
def __rsub__(self, other):
# Get the frame of the caller
frame = inspect.currentframe().f_back
# Get the line of code where the operator is used
line = inspect.getframeinfo(frame).code_context[0]
# Match leading spaces in the line
spaces = re.match(r'^(s*)', line)
# Remove leading spaces from each line in the multiline string
return re.sub(fr'^{spaces.group()}', '', other, flags=re.MULTILINE)
# Example usage
def example_function():
tst = """\n test
dd
dd
d
""" - Lstrip() # Remove leading spaces based on the caller's indentation level
print(tst)
example_function()
在结束引号后直接使用 Lstrip(),因为缩进是在调用 Lstrip 的行上计算的。
解决方案 13:
这取决于您希望文本如何显示。如果您希望所有文本都左对齐,那么请按照第一个代码片段的格式进行格式化,或者遍历所有行并修剪左侧的所有空间。
扫码咨询,免费领取项目管理大礼包!