管理 python 字符串中的关键字参数:如何仅格式化一些参数并保持其他参数未格式化

Managing keyword arguments in python strings: how to format only some arguments and keep the others unformatted

我在理解字符串的 format() 方法的工作方式时遇到了一些麻烦。

假设我设置了一个带有关键字参数的字符串变量:

s = '{hello} {person_name}'

我可以将此值分配给另一个变量或打印它。在后一种情况下,结果将是 {hello} {person_name}.

我还可以在打印 s 时使用 format() 方法并为关键字分配一些值:

print(s.format(hello='hello', person_name='Alice'))

在这种情况下,结果是 hello Alice。当然,我也可以把它赋值给一个新的变量。

当我只想对一个关键字使用格式时,我的问题就出现了:

print(s.format(hello='hello'))

a = s.format(hello='hello')

两者都报错:

KeyError: 'person_name'


我希望能够 运行 像 :

s = '{hello} {person_name}'
a = s.format(hello='hello')
if something:
  b = a.format(person_name='Alice')
else:
  b = a.format(person_name='Bob')
print(b)

是否可以这样,或者我应该在使用 format() 时设置所有关键字吗?

在您的用例中,您可以考虑转义字符串中的 {person}

# double brace the person_name to escape it for the first format
s = '{hello} {{person_name}}'
a = s.format(hello='hello')

# a = 'hello {person_name}'

if something:
  b = a.format(person_name='Alice')
  # b = 'hello Alice'
else:
  b = a.format(person_name='Bob')
  # b = 'hello Bob'

print(b)

但是,使用此方法时,您需要遵循转义变量的明确顺序。也就是说,您必须先分配 hello ,然后分配 person_name。如果您需要灵活处理事物的顺序,我建议在完全传递变量之前使用 dict 构造变量:

# dict approach
s = '{hello} {person_name}'

# determine the first variable
d = {'hello':'hello'}
... do something
d.update({'person': 'Alice'})

# unpack the dictionary as kwargs into your format method
b = s.format(**d)

# b = 'hello Alice'

这使您可以更灵活地处理事物的顺序。但是你必须只调用一次.format() 所有 你的dict中提供的变量(至少它必须有一个默认值),否则它仍然会提高一个错误。

如果你想要更花哨,并希望能够在没有变量的情况下打印字段名称,你也可以制作自己的包装函数:

# wrapper approach
# We'll make use of regex to keep things simple and versatile
import re

def my_format(message, **kwargs):

    # build a regex pattern to catch words+digits within the braces {}
    pat = re.compile('{[\w\d]+}')

    # build a dictionary based on the identified variables within the message provided
    msg_args = {v.strip('{}'): v for v in pat.findall(message)}

    # update the dictionary with provided keyword args
    msg_args.update(kwargs)

    # ... and of course, print it
    print(message.format(**msg_args))

s = 'Why {hello} there {person}'
my_format(s, hello='hey')
# Why hey there {person}

my_format(s, person='Alice') 
# Why {hello} there Alice

您可以通过修改字典理解中的 v 来确定您想要的默认显示(在没有变量的情况下)。

我认为您必须在使用 format() 时定义所有关键字。

我建议使用 *args 的不同方法:

def printHello(*args):
    print(' '.join([arg for arg in args]))

printHello('hello', 'Alice')
# hello Alice
printHello('hello')
# hello

您可以向此函数发送任意数量的单词。

Is something like this possible or should I set all keywords when I use format()?

PEP-3101 说:

If the index or keyword refers to an item that does not exist, then an IndexError/KeyError should be raised.

所以是的,如果您要使用关键字,则必须全部指定。

根据PEP 3101 如果索引或关键字引用不存在的项目,则应提出IndexError/KeyError。

但是您可以像这样创建自己的自定义格式化程序class。

from string import Formatter


class MyStringFormatter(Formatter):
    def get_value(self, key, args, kwds):
        try:
            return super().get_value(key, args, kwds)
        except KeyError:
            return "{%s}" % key

fmt = MyStringFormatter()

演示

s = "{hello} {person_name}"

keywords = {'hello': 'hello'}
a = fmt.format(s, **keywords)
print(a) 
# This will print hello {person_name}

something = False

if something:
    person_name = {'person_name': 'Alice'}
else:
    person_name = {'person_name': 'Bob'}
b = fmt.format(a, **person_name)

print(b)   
# This will print `hello Bob` if `something` is False, 'hello Alice' otherwise.