有没有办法使用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 ""
这似乎提供了理想的行为。
答案 0 :(得分:18)
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()
的第一个参数,就可以传递其他键和值。
答案 1 :(得分:12)
格式映射中字符串的官方解决方案(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}"
答案 2 :(得分:5)
不幸的是,不,默认情况下没有这样的方法。但是,您可以使用覆盖的__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
答案 3 :(得分:2)
我制作的版本与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'