有没有办法使用python string.format,这样当索引丢失时不会抛出异常,而是插入一个空字符串。
result = "i am an {error} example string {error2}".format(hello=2,error2="success")
在这里,结果应该是:
"i am an example string success"
现在,python抛出了一个keyerror并停止格式化。是否有可能改变这种行为?
谢谢
编辑:
存在Template.safe_substitute(即使使模式保持原样而不是插入空字符串),但对于string.format可能没有类似的东西
期望的行为类似于php中的字符串替换。
class Formatter(string.Formatter):
def get_value(self,key,args,kwargs):
try:
if hasattr(key,"__mod__"):
return args[key]
else:
return kwargs[key]
except:
return ""
这似乎提供了期望的行为。
str.format()
不期望一个映射对象。试试这个:
from collections import defaultdict
d = defaultdict(str)
d['error2'] = "success"
s = "i am an {0[error]} example string {0[error2]}"
print s.format(d)
你使用返回“”的str()
工厂制作一个defaultdict。然后为defaultdict创建一个键。在格式字符串中,您可以访问传递的第一个对象的键。这样做的好处是允许你传递其他键和值,只要你的defaultdict是format()
的第一个参数。
格式映射中字符串的官方解决方案(Python 3 Docs)是对dict
类进行子类化并定义魔术方法__missing__()
。只要缺少某个键,就会调用此方法,而它返回的内容则用于字符串格式:
class format_dict(dict):
def __missing__(self, key):
return "..."
d = format_dict({"foo": "name"})
print("My %(foo)s is %(bar)s" % d) # "My name is ..."
print("My {foo} is {bar}".format(**d)) # "My name is ..."
编辑:第二个print()在Python 3.5.3中有效,但它不在例如3.7.2:KeyError: 'bar'
被提升,我找不到抓住它的方法。
经过一些实验,我发现Python的行为有所不同。在v3.5.3中,调用是成功的__getitem__(self, "foo")
和无法找到密钥__getitem__(self, "bar")
的"bar"
,因此它调用__missing__(self, "bar")
来处理丢失的密钥而不抛出KeyError。在v3.7.2中,__getattribute__(self, "keys")
在内部被调用。内置的keys()
方法用于返回键上的迭代器,产生“foo”,__getitem__("foo")
成功,然后迭代器耗尽。对于来自格式字符串的{bar}
,没有关键的"bar"
。 __getitem__()
和__missing_()
没有被要求处理这种情况。而是抛出KeyError。我不知道怎么会抓住它,如果有的话。
在Python 3.2+中你应该使用format_map()
(也见Python Bug Tracker - Issue 6081):
from collections import defaultdict
d = defaultdict(lambda: "...")
d.update({"foo": "name"})
print("My {foo} is {bar}".format_map(d)) // "My name is ..."
如果要保留占位符,可以执行以下操作:
class Default(dict):
def __missing__(self, key):
return key.join("{}")
d = Default({"foo": "name"})
print("My {foo} is {bar}".format_map(d)) // "My name is {bar}"
如你所见,format_map()
确实打电话给__missing__()
。
以下似乎是最兼容的解决方案,因为它也适用于较旧的Python版本,包括2.x(我测试了v2.7.15):
class Default(dict):
def __missing__(self, key):
return key.join("{}")
d = Default({"foo": "name"})
import string
print(string.Formatter().vformat("My {foo} is {bar}", (), d)) // "My name is {bar}"
不幸的是,不,默认情况下没有这样的方法。但是,您可以使用重写的__getattr__
提供defaultdict或object,并使用如下所示:
class SafeFormat(object):
def __init__(self, **kw):
self.__dict = kw
def __getattr__(self, name):
if not name.startswith('__'):
return self.__dict.get(name, '')
print "i am an {0.error} example string {0.error2}".format(SafeFormat(hello=2,error2="success"))
i am an example string success
我创建的版本与Daniel的方法类似,但没有{0.x}属性访问权限。
import string
class SafeFormat(object):
def __init__(self, **kw):
self.__dict = kw
def __getitem__(self, name):
return self.__dict.get(name, '{%s}' % name)
string.Formatter().vformat('{what} {man}', [], SafeFormat(man=2))
打印出来
'{what} 2'