2010-02-04 42 views
3

我經常發現自己使用以下模式進行字符串格式化。在字符串格式中捕獲** vars()模式

a = 3 
b = 'foo' 
c = dict(mykey='myval') 

#prints a is 3, b is foo, mykey is myval 
print('a is {a}, b is {b}, mykey is {c[mykey]}'.format(**vars())) 

也就是說,我經常需要在本地命名空間中打印值,由對vars()的調用表示。然而,當我查看我的代碼時,不斷重複.format(**vars())模式似乎非常不合理。

我想創建一個捕獲此模式的函數。這將是類似於以下內容。

# doesn't work 
def lfmt(s): 
    """ 
    lfmt (local format) will format the string using variables 
    in the caller's local namespace. 
    """ 
    return s.format(**vars()) 

除了通過我在lfmt命名空間就是時間,乏()不再是我想要的。

如何編寫lfmt以便它在調用者的命名空間中執行vars(),以便下面的代碼可以像上面的例子那樣工作?

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}')) 
+3

您的要求似乎違背的Python的精神我不再擁有曾經做過的Python排版,但我想不出有什麼辦法來實現你想要的。 – Sean 2010-02-04 17:57:24

回答

2

編輯:爲使lfmt在從不同名稱空間調用時工作,您需要inspect模塊。注意,如the documentation warns,該inspect模塊可能不適合生產的代碼,因爲它可能不與Python

import inspect 
def lfmt(s): 
    caller = inspect.currentframe().f_back 
    return s.format(**caller.f_locals) 

a = 3 
b = 'foo' 
c = dict(mykey='myval') 

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}')) 
# a is 3, b is foo, mykey is myval 
+0

謝謝。當調用者位於全局名稱空間中時,這種方式起作用,但當調用者位於其他範圍時則不起作用。 – 2010-02-04 18:23:42

+1

@Jason:是的,你說得對。我已經編輯了我的答案,以使lfmt可以在命名空間中工作。 – unutbu 2010-02-04 18:33:57

+0

優秀。幾乎就是這樣。將f_globals更改爲f_locals,這正是我所需要的。 – 2010-02-04 18:35:54

1

您必須檢查調用幀中的變量。

這將讓你開始:

import inspect 
import pprint 

def lfmt(s): 
    for frame in inspect.getouterframes(inspect.currentframe()): 
     f = frame[0] 
     print pprint.pformat(f.f_locals) 
    return '???' 

if __name__ == '__main__': 
    a = 10 
    b = 20 
    c = 30 
    lfmt('test') 
+0

這是一個好的開始......現在讓它工作。 – 2010-02-04 18:25:01

0

給你:

import sys 

def lfmt(s): 
    """ 
    lfmt (local format) will format the string using variables 
    in the caller's local namespace. 
    """ 

    if hasattr(sys, "tracebacklimit") and sys.tracebacklimit == 0: 
     raise Exception, "failfailfail" 

    try: 
     raise ZeroDivisionError 
    except ZeroDivisionError: 
     f = sys.exc_info()[2].tb_frame.f_back 

    return s.format(**f.f_locals) 

a = 5 
somestring = "text" 
print lfmt("{a} {somestring}") 

,它的作品並不意味着你應該使用它的事實。這就是開發人員稱之爲「重大破解」的問題,通常附帶評論「XXX修復我XXX」。

+0

這很好。我認爲有一個更清晰的解決方案,涉及失蹤理論指出的檢查模塊。 – 2010-02-04 18:24:18

0

是這麼差的所有實現合作,鍵入,vars每次調用該函數的時間?

def lfmt(s,v): 
    """ 
    lfmt (local format) will format the string using variables 
    from the dict returned by calling v()""" 
    return s.format(**v()) 

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}',vars)) 
+0

這不是不好,但如果我要經歷創建函數的麻煩,我不會要求調用者每次都傳遞相同的東西,特別是如果有更好的方法。 – 2010-02-04 20:43:26

0

你也可以使用sys代替inspect,但我不知道是否有不同的實現同樣的問題inspect了。

import sys 

def lfmt(s): 
    caller = sys._getframe(1) 
    return s.format(**caller.f_locals) 

這是據我得到了:「顯式優於隱式」 Python string interpolation implementation