2013-05-25 35 views
3

我有一个函数,它不接受任何参数并返回一个字符串,我想用字符串格式来调用它。在这儿,这里是如何我试图使用format修改python的字符串格式化程序

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类来做到这一点?

哈克事情,我认为将是覆盖的cabbages__getattr__方法,我真的不想被“视为病态”(或者,至少,那* *病理)。

+0

使用'str.format()'和'当地人()'通常是一个非常糟糕的主意。只需传递你想要的值。 –

+0

@Lattyware真的,我实际上使用不同的字典,例如(一个可怜的选择)。 –

回答

1

我猜主要的不足我在你的答案看到的是,它不也处理原始化合物的字段名的语法像0.name为“GETATTR” /“点”操作员访问,也没有。 ,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 
+0

谢谢!我没有意识到有2.7/3的差异,这很烦人。此外,我还处于独特的位置,我知道'{s}中的所有内容都可以调用,可能大多数人都不会! –

+0

@安迪:对不起,我错过了。在Python 2.7中,你的答案尽可能地发挥作用,就像我的工作一样。 – martineau

1

可以覆盖的Formatterget_field方法如下:

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' 

做这样的事情配有健康警告,所以我认为这是值得全粘贴的that PEP安全事项一节加重视( ):

在历史上,字符串格式化已的 安全漏洞在公共源基于web的一个特别是如果 字符串格式化系统允许嵌入格式字符串的任意表达式为 。

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

除此之外,次佳方法是确保字符串 格式化没有副作用。由于 Python的开放性,因此不可能保证,任何不平凡的 操作都具有此属性。 PEP的作用是将格式字符串中的 类型的表达式限制为那些可见的 副作用都是Python开发人员文化罕见并极力阻止的表达式。因此,例如,属性访问 被允许的,因为这会被认为是病态写 代码,其中一个属性的光接入有明显的侧代码 影响(是否有无形副作用 - 例如 作为创建一个高速缓存条目更快的查找 - 是无关紧要的)

+0

其中有'self'的代码适用于我(或者我不会编辑你的答案)。 – martineau