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

3 投票
5 回答
1047 浏览
提问于 2025-04-15 18:54

我经常使用以下这种方式来格式化字符串。

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()) 这种写法,感觉有点不太符合 Python 的风格。

我想创建一个函数,能够捕捉到这种写法。它的样子大概是这样的。

# 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

给你看看:

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”。

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

编辑: 为了让 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

撰写回答