5

我有一个不带参数并返回一个字符串的函数,我想使用字符串格式调用它。就是这样,这就是我尝试使用的方式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类来做到这一点?

我考虑的一个骇人听闻的事情是覆盖 的__getattr__方法cabbages,我真的不希望被“认为是病态的”(或者,至少,*that* 病态的)。

4

2 回答 2

2

我想我在您的回答中看到的主要缺陷是它不处理原始复合字段名称语法,例如0.name用于“getattr”/“dot”运算符访问,也不0[name]用于 PEP 3101 中指定的“getitem”检索。

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

虽然它如何检测get_value()方法中的调用有点 hacky,但我不认为它会被认为是病态的。;-)

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
于 2013-05-25T22:28:39.533 回答
1

您可以覆盖如下的get_field方法: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'

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

从历史上看,字符串格式化一直是基于 Web 的应用程序中安全漏洞的常见来源,特别是如果字符串格式化系统允许将任意表达式嵌入到格式字符串中。

在不产生潜在安全漏洞的情况下使用字符串格式化的最佳方法是永远不要使用来自不受信任来源的格式字符串

除此之外,下一个最佳方法是确保字符串格式化没有副作用。由于 Python 的开放性,无法保证任何重要的操作都具有此属性。这个 PEP 所做的是将格式字符串中的表达式类型限制为那些可见副作用既罕见又被 Python 开发人员文化强烈反对的表达式类型。因此,例如,允许属性访问是因为如果编写仅对属性的访问具有可见副作用的代码(代码是否具有不可见的副作用 - 例如创建缓存条目以加快查找速度 - 是无关紧要的)会被认为是病态的。 )

于 2013-05-25T18:45:44.340 回答