Python 以字符串格式捕获**vars()模式
我经常发现自己使用以下模式进行字符串格式化Python 以字符串格式捕获**vars()模式,python,scope,string-formatting,Python,Scope,String Formatting,我经常发现自己使用以下模式进行字符串格式化 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())模式似乎非常
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
命名空间中时,vars()不再是我想要的
如何编写lfmt,使其在调用方的命名空间中执行vars(),从而使下面的代码可以像上面的示例那样工作
print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))
您必须检查调用帧中的变量 这将使您开始:
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')
给你:
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 fix me XXX”。Edit:为了使
lfmt
在从不同名称空间调用时工作,您需要inspect
模块。注意,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
每次调用函数时键入
,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))
您也可以使用
sys
而不是inspect
,但我不知道它在不同的实现中是否存在与inspect
相同的问题
import sys
def lfmt(s):
caller = sys._getframe(1)
return s.format(**caller.f_locals)
就我所知:您的请求似乎与“显式优于隐式”的Python精神背道而驰。我不再像以前那样精通Python,但我想不出任何方法来实现您的愿望。谢谢。当调用者在全局命名空间中时,这种方法有效,但当调用者在其他作用域中时则无效。@Jason:是的,你说得对。我编辑了我的答案,使lfmt能够跨名称空间工作。非常好。差不多了。把f_globals换成f_locals,这正是我想要的。这很好。我认为有一个更干净的解决方案,包括lost theory指出的inspect模块。这还不错,但如果我要经历创建函数的麻烦,我不会每次都要求调用方传递相同的东西,特别是如果有更好的方法的话。