带参数的多行字符串。如何申报?


72

假设我有一个非常长的字符串,其中包含要创建的参数。我知道您可以使用创建多行字符串

cmd = """line 1
      line 2
      line 3"""

但是现在让我说我想传递1、2和3作为参数。

这有效

cmd = """line %d
      line %d
      line %d""" % (1, 2, 3)

但是,如果我有一个包含30个以上参数的超长字符串,那么如何在多行中传递这些参数呢?在单行中传递它们会破坏甚至尝试创建多行字符串的目的。

预先感谢任何人的帮助和见识。

Answers:



89

您可以使用str.format()允许命名参数的函数,因此:

'''line {0}
line {1}
line {2}'''.format(1,2,3)

您当然可以使用Python的*args语法对此进行扩展,以允许您传入tuple或list:

args = (1,2,3)
'''line {0}
line {1}
line {2}'''.format(*args)

如果您可以智能地命名您的参数,那么最健壮的解决方案(尽管最耗费键入内容的解决方案)将是使用Python的**kwargs语法来传递字典:

args = {'arg1':1, 'arg2':2, 'arg3':3}
'''line {arg1}
line {arg2}
line {arg3}'''.format(**args)

有关str.format()迷你语言的更多信息,请访问此处。


1
+1 ** kwargs格式非常适合许多情况下的可读性(尽管可能不是OP的示例)。
— Casey Kuball 2012年

该'''string here'''技术是一种可靠的技术,效果很好,但是当您必须左对齐除第一行以外的所有代码并且源代码缩进几个级别时,它会创建一些非常丑陋的源代码。因此,要获得具有良好对齐方式的漂亮且易于查看的源代码,请改用我的技术:stackoverflow.com/a/54564926/4561887。当然,它有其缺点,但是对于少于一长段文字的任何内容,我喜欢使用另一种技巧而不是使用该''' '''技巧。
— 加布里埃尔·斯台普斯

将此自文档文档字符串打印作为模块文档进行检查,它使用您在上面介绍的技术类型。我只是将其添加到此处的答案底部:stackoverflow.com/a/54564926/4561887。
— 加布里埃尔·斯台普斯

如果您的字符串中有花括号,请使用双花括号将其转义:{{和}}
— LoMaPh

24

最简单的方法可能是使用文字字符串插值(可从Python 3.6开始使用,并假设所有参数都在范围内)。

cmd = f"""line {1}
      line {2}
      line {3}"""

谢谢,但是在原始字符串包含很多括号的情况下,这种方法不能很好地工作
— Luk Aron

16

具有string.format()-Function的另一种变体。

s = "{0} " \
    "{1} " \
    "{2}" \
    .format("Hello", "world", "from a multiline string")    
print(s)

5

2020年10月19日更新:尽管我的回答仍然很有见识,内容丰富且值得一读,但现在我在这里有了一个更好的答案,这取决于真正有用的textwrap.dedent()功能。


正如@Chinmay Kanchi所说,您可以执行以下操作:

'''line {0}
line {1}
line {2}'''.format(1,2,3)

但是,我认为它看起来有点愚蠢,必须在新行上左对齐,尤其是当您执行此操作时,已经缩进了多个级别,因此我更喜欢这样写:

'''line {0}
   line {1}
   line {2}'''.format(1,2,3)

可行,但错误!它可将所有空格左边的line {1}和line {2}作为真正的空间,所以在印刷它看起来愚蠢的:

1
   2
   3

代替

1
2
3

因此,一种解决方法是使用+运算符进行连接,并在连接的字符串以及显式换行(\n)字符周围加括号,如下所示:

('line {0}\n' + 
 'line {1}\n' +
 'line {2}').format(1,2,3)

完美(在我看来)!现在,如果您将其打印出来,它在源代码和实际字符串中看起来都很好并且对齐了。

完整示例:

丑陋的源代码!

num1 = 7
num2 = 100
num3 = 75.49

# Get some levels of indentation to really show the effect well.
# THIS IS *UGLY*! Notice the weird forced-left-align thing for the string I want to print!
if (True):
    if (True):
        if (True):
            # AAAAAH! This is hard to look at!
            print('''num1 = {}
num2 = {}
num3 = {}'''.format(num1, num2, num3))

            # More lines of code go here
            # etc
            # etc

输出:

num1 = 7
num2 = 100
num3 = 75.49

漂亮的例子!啊,很高兴在源代码中查看。:)

这就是我的偏爱。

# Get some levels of indentation to really show the effect well.
if (True):
    if (True):
        if (True):
            # IMPORTANT: the extra set of parenthesis to tie all of the concatenated strings together here is *required*!
            print(('num1 = {}\n' + 
                   'num2 = {}\n' + 
                   'num3 = {}')
                   .format(num1, num2, num3))

            # More lines of code go here
            # etc
            # etc

输出:

num1 = 7
num2 = 100
num3 = 75.49

2019年5月21日更新:有时“丑陋”的多行字符串确实是最好的选择!

因此,我一直在使用Python从基于文本的配置文件中自动生成C头文件和源(.h / .c)文件,经过大量的研究后,我得出结论,简单地复制-将来自配置文件的大量文本粘贴到我的Python脚本中,胜过任何“丑陋”因素。

因此,我确定当需要大的,多行复制粘贴的字符串时,例如,以下是我这样做的首选方式:

选项1:

  • 在整个长字符串周围使用括号,以使开头"""可以换行

    获得一定程度的压痕以仍然显示“丑陋”效果。

    if(True):if(True):if(True):header =(“”“ / *我的自定义文件头信息* /

    #pragma一次

    #include“ {}”

    const {} {}; “”“).format(包括,struct_t,struct)

              print("header =" + header)
    

选项2:

  • 没有括号,但仍将结束符"""放在自己的行上

    获得一定程度的压痕以仍然显示“丑陋”效果。

    if(True):if(True):if(True):header =“”“ / *我的自定义文件标题信息* /

    #pragma一次

    #include“ {}”

    const {} {}; “”“ .format(包括,struct_t,struct)

              print("header =" + header)
    

选项3:

  • 整个字符串周围没有括号,并将结束"""符与字符串内容放在同一行上,以防止\n在末尾添加(可能不希望出现)。

  • 但是,format(如果很长,请将其余部分放在新行(或许多新行)上。

    获得一定程度的压痕以仍然显示“丑陋”效果。

    if(True):if(True):if(True):header =“”“ / *我的自定义文件标题信息* /

    #pragma一次

    #include“ {}”

    const {} {};“”“。format(include,struct_t,struct)#缩进实际上可以是任何东西,但我喜欢缩进1级;因为它在括号内,但是没关系

              print("header =" + header)
    

输出:

  • 选项1和2产生完全相同的输出,\n在字符串的末尾有一个额外的输出,在大多数情况下都可以
  • 选项3产生与选项1和2完全相同的输出,除了它确实不能有额外的\n在字符串的结尾处,在情况下是不希望你的情况
  • 究竟使用选项1、2还是3都不重要-这只是用户的偏好,除了额外的 \n上面提到

这是上面的选项1、2和3所打印的内容:

/*
my custom file header info here
*/

#pragma once

#include "<stdint.h>"

const my_struct_t my_struct;


将所有内容放在一起:混合使用“漂亮”和“丑陋”方法以获得最佳打印效果为模块文档字符串文档的!

这是同时使用上面介绍的“漂亮”和“丑陋”多行字符串方法以获得每种方法的最大好处的基本示例。这也显示了如何使用和打印模块“文档字符串”来记录您的模块。请注意,"""基于-的多行技术如何为我们提供了很大的间距,因为\n在打开之后"""和关闭之前,在行下方我会自动进行换行(),"""因为这是字符串的编写方式。

# PRETTY, AND GOOD.
print("\n\n" + 
      "########################\n" + 
      "PRINT DOCSTRING DEMO:\n" + 
      "########################")

import sys

def printDocstrings():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # A LITTLE BIT UGLY, BUT GOOD! THIS WORKS GREAT HERE!
    print("""
---------------------
Module Documentation:
---------------------
printDocstrings:{}
myFunc1:{}
class Math:{}
    __init__:{}
    add:{}
    subtract:{}""".format(
        printDocstrings.__doc__,
        myFunc1.__doc__,
        Math.__doc__,
        Math.__init__.__doc__,
        Math.add.__doc__,
        Math.subtract.__doc__))

    sys.exit()

def myFunc1():
    """
    Do something.
    Params:  NA
    Returns: NA
    """
    pass

class Math:
    """
    A basic "math" class to add and subtract
    """

    def __init__(self):
        """
        New object initialization function.
        Params:  NA
        Returns: NA
        """
        pass

    def add(a, b):
        """
        Add a and b together.
        Params:  a   1st number to add
                 b   2nd number to add
        Returns: the sum of a + b
        """
        return a + b

    def subtract(a, b):
        """
        Subtract b from a.
        Params:  a   number to subtract from
                 b   number to subtract
        Returns: the result of a - b
        """
        return a - b

printDocstrings() 

输出:
-请注意,这一切都是多么漂亮和合理,因为以这种方式打印它们时,它们的选项卡,换行符和文档字符串的间距都将自动保留!

  
########################  
PRINT DOCSTRING DEMO:  
########################  
  
---------------------  
Module Documentation:  
---------------------  
printDocstrings:  
    Print all document strings for this module, then exit.  
    Params:  NA  
    Returns: NA  
      
myFunc1:  
    Do something.  
    Params:  NA  
    Returns: NA  
      
class Math:  
    A basic "math" class to add and subtract  
      
    __init__:  
        New object initialization function.  
        Params:  NA  
        Returns: NA  
          
    add:  
        Add a and b together.  
        Params:  a   1st number to add  
                 b   2nd number to add  
        Returns: the sum of a + b  
          
    subtract:  
        Subtract b from a.  
        Params:  a   number to subtract from  
                 b   number to subtract  
        Returns: the result of a - b  
          
  

参考文献:

  1. Python文档字符串:https://www.geeksforgeeks.org/python-docstrings/
  • 注意:您也可以使用该help()方法访问模块或类的文档(但以交互方式),如上面的链接所示,如下所示:

         help(Math)  # to interactively display Class docstring
         help(Math.add)  # to interactively display method's docstring 
    

4

要在插入的同一行中包含参数,可以执行以下操作:

cmd = "line %d\n"%1 +\
      "line %d\n"%2 +\
      "line %d\n"%3

[编辑:]在回应第一个评论时,我提出了以下建议:

cmd = "\n".join([
      "line %d"%1,
      "line %d"%2,
      "line %d"%3])

用30个以上的参数执行此操作效率不高。"".join()列表,而另一方面... :)上
— 弗雷德里克·哈米迪

3

您可以用来textwrap.dedent从行中删除前导空格:

import textwrap

cmd = str.strip(textwrap.dedent(
    '''
        line {}
            line with indent
        line {}
        line {}
    '''
    .format(1, 2, 3)))

结果是:

line 1
    line with indent
line 2
line 3

请对使用PyCharm的人进行投票:youtrack.jetbrains.com/issue/PY-34646。问题的摘要中自动格式化的功能和格式化检查规则不一致。
— 乔治·索维托夫

2

这对我有用:

cmd = """line %d
      line %d
      line %d""" % (
          1,
          2,
          3
      )

2

TLDR;

直接跳下来,查看下面的示例1和4。

完整答案:

上周(2020年10月),我才刚刚了解到Pythontextwrap模块,它具有非常方便的textwrap.dedent()功能,并且考虑到自python 2.7以来就已经存在,我不敢相信它并不流行!

textwrap.dedent()在多行字符串周围使用可解决我先前回答的所有问题!

这是关于它的官方文档(加了重点):

textwrap.dedent(text)

从文本的每一行中删除所有常见的前导空格。

这可以使三引号字符串与显示的左边缘对齐,同时仍将它们以缩进形式显示在源代码中。

请注意,制表符和空格都被视为空格,但它们并不相等:行" hello"和"\thello"被认为没有共同的前导空白。

仅包含空格的行在输入中被忽略,并在输出中标准化为单个换行符。

例如:

def test():
    # end first line with \ to avoid the empty line!
    s = '''\
    hello
      world
    '''
    print(repr(s))          # prints '    hello\n      world\n    '
    print(repr(dedent(s)))  # prints 'hello\n  world\n'

对于所有示例

import textwrap

例子1

因此,而不是this,正如最受好评的答案所言(这会失去美观,简洁的缩进):

cmd = '''line {0}
line {1}
line {2}'''.format(1,2,3)

print(cmd)

做到这一点(并保持良好,干净,缩进的状态)!

cmd = textwrap.dedent('''\
    line {0}
    line {1}
    line {2}''').format(1,2,3)

print(cmd)

例子2

如果该format()函数有很多参数,则可以根据需要将它们放在多行中。注意,这里的format()参数占两行:

cmd = textwrap.dedent('''\
    line {0}
    line {1}
    line {2}
    line {3}
    line {4}
    line {5}
    line {6}
    line {7}
    line {8}
    line {9}
    line {10}
    line {11}
    line {12}
    line {13}
    line {14}
    line {15}
    line {16}
    line {17}
    line {18}
    line {19}''').format(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
        11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    )

print(cmd)

当然,如果format()参数真的很长,您也可以将每个参数放在自己的行上:

cmd = textwrap.dedent('''\
    line {0}
    line {1}
    line {2}
    line {3}
    line {4}
    line {5}
    line {6}
    line {7}
    line {8}
    line {9}
    line {10}
    line {11}
    line {12}
    line {13}
    line {14}
    line {15}
    line {16}
    line {17}
    line {18}
    line {19}''').format(
        100000000000000000000000000000000000000000000000000000000000000000001,
        100000000000000000000000000000000000000000000000000000000000000000002,
        100000000000000000000000000000000000000000000000000000000000000000003,
        100000000000000000000000000000000000000000000000000000000000000000004,
        100000000000000000000000000000000000000000000000000000000000000000005,
        100000000000000000000000000000000000000000000000000000000000000000006,
        100000000000000000000000000000000000000000000000000000000000000000007,
        100000000000000000000000000000000000000000000000000000000000000000008,
        100000000000000000000000000000000000000000000000000000000000000000009,
        100000000000000000000000000000000000000000000000000000000000000000010,
        100000000000000000000000000000000000000000000000000000000000000000011,
        100000000000000000000000000000000000000000000000000000000000000000012,
        100000000000000000000000000000000000000000000000000000000000000000013,
        100000000000000000000000000000000000000000000000000000000000000000014,
        100000000000000000000000000000000000000000000000000000000000000000015,
        100000000000000000000000000000000000000000000000000000000000000000016,
        100000000000000000000000000000000000000000000000000000000000000000017,
        100000000000000000000000000000000000000000000000000000000000000000018,
        100000000000000000000000000000000000000000000000000000000000000000019,
        100000000000000000000000000000000000000000000000000000000000000000020,
    )

print(cmd)

例子3

而不是这个,正如我在原来的答复说(而保持好看的缩进,但有点乏味使用):

print("\n\n" + 
      "########################\n" + 
      "PRINT DOCSTRING DEMO:\n" + 
      "########################")

...您现在可以执行此操作!-允许我的多行字符串在打印时“与显示器的左边缘对齐,同时仍将它们以缩进形式显示在源代码中”(请参见官方文档):

# Note: use the `\` below to prevent the implicit newline right after it from being printed.
print(textwrap.dedent("""

      ########################
      PRINT DOCSTRING DEMO:
      ########################\
      """))

例子4

而不是,它中间有一些难看的缩进:

def printDocstrings1():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # A LITTLE BIT UGLY, BUT IT WORKS.
    print("""
---------------------
Module Documentation:
---------------------
printDocstrings:{}
myFunc1:{}
class Math:{}
    __init__:{}
    add:{}
    subtract:{}""".format(
        printDocstrings1.__doc__,
        myFunc1.__doc__,
        Math.__doc__,
        Math.__init__.__doc__,
        Math.add.__doc__,
        Math.subtract.__doc__))

...执行此操作,它textwrap.dedent()始终使外观缩进!:

def printDocstrings2():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # MUCH CLEANER! Now I can have the proper indentation on the left withOUT
    # it printing that indentation!
    print(textwrap.dedent("""\
    ---------------------
    Module Documentation:
    ---------------------
    printDocstrings:{}
    myFunc1:{}
    class Math:{}
        __init__:{}
        add:{}
        subtract:{}""").format(
            printDocstrings2.__doc__,
            myFunc1.__doc__,
            Math.__doc__,
            Math.__init__.__doc__,
            Math.add.__doc__,
            Math.subtract.__doc__))

运行上面的代码

您可以在我的eRCaGuy_hello_world GitHub存储库中在上面运行我的测试代码:textwrap_practice_1.py。

运行命令:

./textwrap_practice_1.py

要么:

python3 textwrap_practice_1.py

1

这是最简单的版本,就检查format参数而言,它也是IDE友好的:

cmd = (
    'line {}\n'
    'line {}\n'
    'line {}\n'
    .format(1, 2, 3))

多行参数版本:

cmd = (
    'line {}\n'
    'line {}\n'
    'line {}\n'
    .format(
        'very very very very very very very very very long 1',
        'very very very very very very very very very long 2',
        'very very very very very very very very very long 3',
    )
)

请对使用PyCharm的人进行投票:youtrack.jetbrains.com/issue/PY-34646。问题的摘要中的自动格式化和格式化检查不一致。
— 乔治·索维托夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.