2013-05-25 62 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