如果foo中不存在该键,忽略str.format(**foo)。

4

我正在尝试制作一份电子邮件模板。信息内容将取决于字典中的值。然而,每次字典可能不包含所有键。

目前情况还好,因为字典中包含所有的值 ('Title', 'Surname', 'Additional Details'):

practise_dict = {"Additional Details":"blah blah blah blah", "Title": "Mr", "Surname": "Smith", "URL": "/test/tester"}

msg = """From: John Smith <no-reply@somethingsomething.co.uk>
To: {Title} {Surname} <blah@blahblah.co.uk>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
{Additional Details}
<b>This is HTML message.</b>
<h1>This is headline.</h1>
`""".format(**practise_dict)

print(msg)

在变量 msg 中,我正在尝试创建我的“模板”。这意味着我需要拥有字典中可能出现的所有项目。
例如,下面的代码将会失败,因为它要寻找在字典中不存在的 'Date'
practise_dict = {"Additional Details":"blah blah blah blah", "Title": "Mr", "Surname": "Smith", "URL": "/test/tester"}

msg = """From: John Smith <no-reply@somethingsomething.co.uk>
To: {Title} {Surname} <blah@blahblah.co.uk>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
{Additional Details}
{Date}
<b>This is HTML message.</b>
<h1>This is headline.</h1>
`""".format(**practise_dict)

print(msg)

有没有办法让它忽略字符串替换,如果在查找字典中不存在该键?

相关链接:https://dev59.com/gWIj5IYBdhLWcg3wHhz_ - jonrsharpe
4个回答

9
你可以使用Templatesafe_substitute 来实现这一点:
from string import Template

practise_dict = {"Additional_Details":"blah blah blah blah", "Title": "Mr", "Surname": "Smith", "URL": "/test/tester"}

msg = """From: John Smith <no-reply@somethingsomething.co.uk>
To: $Title $Surname <blah@blahblah.co.uk>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
$Additional_Details
$Date
<b>This is HTML message.</b>
<h1>This is headline.</h1>
`"""

s = Template(msg).safe_substitute(**practise_dict)
print(s)

输出

From: John Smith <no-reply@somethingsomething.co.uk>
To: Mr Smith <blah@blahblah.co.uk>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
blah blah blah blah
$Date
<b>This is HTML message.</b>
<h1>This is headline.</h1>

2
很好,我不知道Template/safe_substitute - jonrsharpe
1
太好了,谢谢。实际上,我已经结合使用了这些解决方案。我正在使用默认字典和safe_substitute的这个想法。谢谢你们两个。 - Bombington
2
一个很好的envsubst(1)替代品。非常感谢。 - Johnny Utahh

2
我认为无法告诉format一些替换是可选的。然而,这里有两种解决方法。

如果只有一个缺失字段,请尝试以下方法:

msg = """...""".format(Date=practise_dict.pop("Date", ""), # handle optional field
                       **practise_dict) # pass the rest as before

然而,请注意这会修改practise_dict,如果有多个值需要处理,这将会很麻烦。

如果可能会有多个字段缺失,或者不想修改字典,以下方法可能更可取:

defaults = {"Date": "", "Additional Details": ""} # define optional fields
defaults.update(practise_dict) # override user data where available
msg = """...""".format(**defaults)

两种方法仍将无法为您未明确提供替代方案的键提供支持,这使得您可以使一些字段成为强制性。


1

如果您还不知道键:

您可以编写一个字典子类,如果在字典中找不到键,则返回该键:

class FailsafeDict(dict):
    def __getitem__(self, item):
        try:
            return super().__getitem__(item)
        except KeyError:
            return "{" + str(item) + "}"
        # end try
    # end def
# end class

这个方法通过重写__getitem__(item)函数来实现,该函数处理dict[item]的调用。

你可以像这样使用它:

f = FailsafeDict({"yo": "lo", "foo": "bar"})
text = "{yo}! {lol}! {foo}!".format(**f)
print(text)  

这将打印出lo! {lol}! bar!

在您的情况下,应该是这样的

msg = """...""".format(**FailsafeDict(practise_dict))

text = "{yo}! {lol}! {foo}!".format(**f) 仍然给我 KeyError。我使用的是 Python 3.10.9 版本。 - Bolong

0
我无法在@luckydonald的回答中发表评论,所以我会在这里添加我的评论。应该使用format_map()而不是传统的format()
class FailsafeDict(dict):
    def __getitem__(self, item):
        try:
            return super().__getitem__(item)
        except KeyError:
            return "{" + str(item) + "}"

f = FailsafeDict({"yo": "lo", "foo": "bar"})
text = "{yo}! {lol}! {foo}!".format_map(f)
print(text) 

> "lo! {lol}! bar!"

你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的回答是否正确。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接