python字符串格式suppress / silent keyerror / indexerror

时间:2010-08-21 04:16:08

标签: string format python

有没有办法使用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 ""

这似乎提供了理想的行为。

4 个答案:

答案 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()的第一个参数,就可以传递其他键和值。

另请参阅http://bugs.python.org/issue6081

答案 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'