在字符串格式化中捕获** vars()模式

时间:2010-02-04 17:43:17

标签: 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())模式似乎非常麻烦。

我想创建一个捕获此模式的函数。它将类似于以下内容。

# 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]}'))

5 个答案:

答案 0 :(得分: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

答案 1 :(得分: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')

答案 2 :(得分: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”。

答案 3 :(得分: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))

答案 4 :(得分:0)

您也可以使用sys代替inspect,但我不知道它与inspect的实现方式是否存在相同的问题。

import sys

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

据我所知:Python string interpolation implementation