String python字符串格式抑制/静默键错误/索引器错误

String python字符串格式抑制/静默键错误/索引器错误,string,format,python,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抛出一个键错误并停止格式化。有可能改变这种行为吗 谢谢 编辑: 存在Template.safe_sub

是否有一种方法可以使用python string.format,以便在缺少索引时不会引发异常,而是插入一个空字符串

result = "i am an {error} example string {error2}".format(hello=2,error2="success")
在这里,结果应该是:

"i am an   example string success"
现在,python抛出一个键错误并停止格式化。有可能改变这种行为吗

谢谢

编辑:

存在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 ""

这似乎提供了所需的行为。

不幸的是,没有,默认情况下没有这样的方法。但是,您可以为其提供defaultdict或对象,并使用以下命令:

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
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是格式化的第一个参数,就可以传递其他键和值


另外,请参见

我制作了一个版本,其工作原理与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'
格式映射中字符串的官方解决方案是对dict类进行子类化,并定义magic方法\uuuuu missing\uuuuuu。只要缺少键,就会调用此方法,它返回的内容将用于字符串格式:

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 ..."
编辑:第二个打印在Python 3.5.3中工作,但在例如3.7.2:KeyError中不工作:“bar”被提升,我无法找到捕捉它的方法

经过一些实验,我发现Python的行为有所不同。在v3.5.3中,调用是成功的_getitem__self和找不到键栏的_getitem__self,bar,因此它调用_missing__self,bar来处理缺少的键,而不会抛出键错误。在v3.7.2中,键在内部被调用。内置的keys方法用于在键上返回迭代器,这将生成foo,_getitem__foo成功,然后迭代器将耗尽。对于格式字符串中的{bar},没有键栏__不会调用getitem_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。相反,会抛出KeyError。我不知道怎么能抓住它,如果有的话

在Python 3.2+中,您应该改用format_map,另请参见:

如果要保留占位符,可以执行以下操作:

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确实调用了uuu missing_uuuu

以下似乎是最兼容的解决方案,因为它也适用于较旧的Python版本,包括2.x I tested 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}"

按原样保留占位符,包括格式规范,例如。{bar:谢谢。它很有用,但正如Fabian所提到的,除了dict之外,它不处理映射对象。这可以通过在bug report链接中使用formatter对象而不是defaultdict来改进吗?这样,就不需要对format变量进行任何更改。Thanksclass Formatterstring.formatter:def get_valueself,key,args,kwargs:try:如果hasattrkey,则mod:return args[key]否则:return kwargs[key]除了:return这对我来说很有用。优点是不需要创建额外的defaultdict。是的,这很好。我不知道如何比较额外defaultdict的惩罚与额外Formatter类+对象的惩罚,但在某些情况下可能更好,尤其是如果代码清晰的话要返回任意字符串,可以使用lambda表达式,因为defaultdict需要一个可调用的:Hello{name}!.format**defaultdictlambda:World Result:Hello World!我不确定defaultdict是否曾经用作关键字args,但在Python 3.8中,@CodeManX的最新建议不起作用。您也可以使用str.format_map,如中所述。我刚刚尝试过,您可以这样做:'some{thing}“.formatformat_dict'your arguments”:它有效地消除了KeyError,并用返回丢失的魔术函数的任何内容替换标记。.format**format_dict{foo:name}当然,也可以使用。由于语法错误,您的代码片段会失败。DIST解包**是强制的.FALSE,IS不直接接受DICTS。考虑返回{'++KEY+}}。'而不是…from _; missing __;适用于如果替换dict中的文本不是有效键,则希望大括号内的文本保持不变的情况。一个很好的示例是HTML模板替换,其中模板包含带有规则集的标记,这些规则集位于大括号内,您希望不受干扰。我尝试了这个方法,但没有成功。我认为您是想使用表单at_地图而不是format@santileortiz我添加了额外的解决方案,并解释了为什么我的原始答案在最近的Python版本中不再有效。我还添加了一个示例,该示例将占位符保留在字符串中,类似于MikeEllis sugge 受激发射损耗。
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}"
import string

class Unformatted:
    def __init__(self, key):
        self.key = key
    def format(self, format_spec):
        return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")

class Formatter(string.Formatter):
    def vformat(self, format_string, args, kwargs):
        return super().vformat(format_string, args, kwargs)
    def get_value(self, key, args, kwargs):
        if isinstance(key, int):
            try:
                return args[key]
            except IndexError:
                return Unformatted(key)
        else:
            try:
                return kwargs[key]
            except KeyError:
                return Unformatted(key)

    def format_field(self, value, format_spec):
        if isinstance(value, Unformatted):
            return value.format(format_spec)
        else:
            return format(value, format_spec)

f = Formatter()
s1 = f.vformat("My {0} {1} {foo:<10} is {bar:<15}!", ["real"], {"foo": "name"})
s2 = f.vformat(s1, [None, "actual"], {"bar":"Geraldine"})
print(s1) # "My real {1} name       is {bar:<15}!"
print(s2) # "My real actual name       is Geraldine      !"
s1 = f.format("My {0} {1} {foo:<10} is {bar:<15}!", "real", foo="name")
s2 = f.format(s1, None, "actual", bar="Geraldine")