在Python中格式化字符串和命名参数


72

情况1:

"{arg1} {arg2}".format(10, 20)

它将给出,KeyError: 'arg1'因为我没有传递命名参数。

情况2:

"{arg1} {arg2}".format(arg1=10, arg2=20)

现在它将正常运行,因为我传递了命名参数。它打印'10 20'

情况3:

而且,如果我输入了错误的名称,它将显示 KeyError: 'arg1'

"{arg1} {arg2}".format(wrong=10, arg2=20)

但,

情况4:

如果我以错误的顺序传递了命名参数

"{arg1} {arg2}".format(arg2=10, arg1=20)

有用...

它打印 '20 10'

我的问题是为什么它起作用,在这种情况下命名参数的用途是什么。


我认为它们只是为了提高可读性。
svineet

11
因为它按名称而不是位置查找...您认为命名参数意味着什么?
aaa90210 2015年

2
看起来您只是将arg2重命名为arg1,反之亦然。换句话说,arg1现在是20而不是10,这就是为什么在字符串打印中看到第一个数字20而不是10的原因。要进行所需的测试,您只需将args及其值移到新位置。 format()调用,它将按照您期望的方式运行。这里没有什么不寻常的。
Brad P.

Answers:


123

命名替换字段({...}在零件格式字符串)匹配针对关键字参数.format()方法,而不是位置参数

关键字参数就像字典中的键。顺序无关紧要,因为它们与name匹配。

如果要与位置参数匹配,请使用数字:

"{0} {1}".format(10, 20)

在Python 2.7及更高版本中,您可以省略数字。{}然后,替换字段将按照格式字符串中出现的顺序自动编号:

"{} {}".format(10, 20) 

格式字符串可以与位置参数关键字参数匹配,并且可以多次使用参数:

"{1} {ham} {0} {foo} {1}".format(10, 20, foo='bar', ham='spam')

引用格式字符串规范

所述FIELD_NAME本身开始于arg_name要么是数字或关键字。如果是数字,则表示位置参数,如果是关键字,则表示命名关键字参数。

强调我的。

如果要创建较大的格式字符串,则使用命名替换字段通常更易读和可维护,因此您不必继续计算参数并弄清楚什么参数会出现在结果字符串中。

您还可以使用**keywords调用语法将现有字典应用于某种格式,从而轻松将CSV文件转换为格式化输出:

import csv

fields = ('category', 'code', 'price', 'description', 'link', 'picture', 'plans')
table_row = '''\
    <tr>
      <td><img src="{picture}"></td>
      <td><a href="{link}">{description}</a> ({price:.2f})</td>
   </tr>
'''

with open(filename, 'rb') as infile:
    reader = csv.DictReader(infile, fieldnames=fields, delimiter='\t')
    for row in reader:
        row['price'] = float(row['price'])  # needed to make `.2f` formatting work
        print table_row.format(**row)

这里picturelinkdescriptionprice是在所有按键row的字典,这是很容易看个究竟时,我运用row到格式化字符串。


3
它不仅更具可读性,而且在使用自然语言和“国际化”(i18n)时非常有用,在这种情况下,您有时希望格式化消息的特定部分以不同的语言以不同的顺序出现。
托雷克

1
@torek:我什至不会去讨论模板中的不同顺序;关键是每个插槽都引用一个特定的参数。您也可以在模板中以不同顺序放置位置参数。
马亭皮特斯

4

额外的好处包括

  • 不必担心参数的顺序。它们将位于格式器中名称所指示的字符串中的正确位置。
  • 您可以将同一参数两次输入一个字符串,而不必重复该参数。例如,"{foo} {foo}".format(foo="bar")给出“ bar bar”

请注意,您可以提供额外的参数而不会导致错误。这一切在以下情况下特别有用

  • 您以后更改字符串格式化程序的更改较少,从而减少了错误发生的可能性。如果它不包含新的命名参数,那么format函数仍将继续工作而无需更改参数,并将参数放在格式化程序中您指示它们的位置。
  • 您可以有多个共享一组参数的格式化程序字符串。例如,在这种情况下,您可以拥有一个包含所有参数的字典,然后根据需要在格式化程序中选择它们。

例如:

>d = {"foo":"bar", "test":"case", "dead":"beef"}
>print("I need foo ({foo}) and dead ({dead})".format(**d))
>print("I need test ({test}) and foo ({foo}) and then test again ({test})".format(**d))
I need foo (bar) and dead (beef)
I need test (case) and foo (bar) and then test again (case)

最后一个示例是我见过的最方便的Python模板化字符串编码方法之一。特别是我不知道有可能将字典参数传递给format并非所有键实际上都出现在格式字符串中的位置。感谢您指出了这一点!
starturtle
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.