修改python的字符串Formatter

时间:2013-05-25 18:45:44

标签: python string

我有一个不带参数的函数并返回一个字符串,我想用字符串格式调用它。这就是,这就是我尝试使用format

的方式
def cabbages():
    return 'hello'

In [2]: '{cabbages} world'.format(**locals())
Out[2]: '<function cabbages at 0x101f75578> world'

In [3]: '{cabbages()} world'.format(**locals())
KeyError: 'cabbages()'

所以这两者都不是我想要的,即cabbages()的价值。

PEP 3101描述了string.Formatter可被覆盖的某种方式,但似乎没有提供很多示例。如何对字符串Formatter类进行子类化/自定义来执行此操作?

我考虑的一个hacky事件是覆盖__getattr__的{​​{1}}方法,我真的不希望被“视为病态”(或,至少,* * * pathological)。

2 个答案:

答案 0 :(得分:2)

我想我在你的答案中看到的主要缺点是,它还没有处理原始的复合字段名称语法,例如0.name用于'getattr'/'dot'操作员访问,0[name]用于在PEP 3101中指定的'getitem'检索。

这是一个适用于Python 2.7和3.3的版本。一个主要的实现差异是它覆盖get_value()方法而不是get_field()

虽然它在如何检测get_value()方法中的调用方面有些苛刻,但我认为它不会被视为病态。 ; - )

from __future__ import print_function

from string import Formatter

class CallFormatter(Formatter):
    try:  # deal with Py 2 & 3 difference
        NUMERICS = (int, long)
    except NameError:
        NUMERICS = int

    def get_value(self, key, args, kwargs):
        if key.endswith('()'):  # call?
            return kwargs[key[:-2]]()
        elif isinstance(key, self.NUMERICS):
            return args[key]
        else:
            return kwargs[key]

if __name__ == '__main__':
    fmt = CallFormatter()

    def cabbages():
        return 'hello'

    d = dict(name='Fred')

    class Thing(object):
        def __init__(self, value):
            self.attr = value
    th = Thing(42)

    print('d[name]:{d[name]}, th.attr:{th.attr}, '
          'cabbages:{cabbages}'.format(**locals()))
    print(fmt.format('d[name]:{d[name]}, th.attr:{th.attr}, '
                     'cabbages:{cabbages}, cabbages():{cabbages()}', 
                     **locals()))

输出:

d[name]:Fred, th.attr:42, cabbages:<function cabbages at 0x00BB05F0>
d[name]:Fred, th.attr:42, cabbages:<function cabbages at 0x00BB05F0>, 
                          cabbages():hello

答案 1 :(得分:1)

您可以按如下方式覆盖Formatter from string import Formatter class CallFormatter(Formatter): def get_field(self, field_name, *args, **kwargs): obj, used_key = Formatter.get_field(self, field_name, *args, **kwargs) return obj(), used_key # obj is the function fmt = CallFormatter() In [11]: fmt.format('{cabbages} world', **locals()) Out[11]: 'hello world' 方法:

{{1}}

做这样的事情带有健康警告,所以我认为值得完全粘贴get_field的安全注意事项部分(强调添加):

  

历史上,字符串格式化是的常见来源       基于Web的应用程序中的安全漏洞,尤其是在       字符串格式化系统允许任意表达式       嵌入格式字符串。

     

使用字符串格式化的最佳方式       创建潜在的安全漏洞是从不使用格式字符串       来自不受信任的来源

     

除此之外,下一个最好的方法是确保字符串       格式化没有副作用。因为开放性       Python,无法保证任何非平凡的       操作有这个属性。 PEP的作用是限制       格式字符串中的表达式类型与可见的格式       副作用既罕见又强烈劝阻       Python开发人员的文化。例如,属性访问       是允许的,因为写入会被认为是病态的       仅仅访问属性的代码具有可见的一面       效果(代码是否具有不可见副作用 - 如此       为更快的查找创建缓存条目 - 无关紧要。)