【问题标题】:Capturing **vars() pattern in string formatting以字符串格式捕获 **vars() 模式
【发布时间】:2010-02-04 17:43:16
【问题描述】:

我经常发现自己使用以下模式进行字符串格式化。

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

【问题讨论】:

  • 您的请求似乎违背了“显式胜于隐式”的 Python 精神。我不再完全拥有我曾经做过的 Python 印章,但我想不出任何方法来完成你想要的。

标签: python scope string-formatting


【解决方案1】:

编辑:为了让lfmt 在从不同命名空间调用时工作,您需要inspect 模块。请注意,作为the documentation warnsinspect 模块可能不适合生产代码,因为它可能不适用于 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

【讨论】:

  • 谢谢。这在调用者在全局命名空间中时有效,但在调用者在其他范围内时无效。
  • @Jason:是的,你是对的。我已经编辑了我的答案以使 lfmt 跨命名空间工作。
  • 优秀。差不多就是这样。将 f_globals 更改为 f_locals,这正是我想要的。
【解决方案2】:

您必须检查调用帧中的变量。

这会让你开始:

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')

【讨论】:

    【解决方案3】:

    你在这里:

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

    【讨论】:

    • 这很好。而且我认为有一个更清洁的解决方案,它涉及 lost-theory 指出的检查模块。
    【解决方案4】:

    每次调用函数时都输入,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))
    

    【讨论】:

    • 这不是那么坏,但如果我要经历创建函数的麻烦,我不会要求调用者传递同样的东西每次,尤其是如果有更好的方法。
    【解决方案5】:

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

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

    据我所知:Python string interpolation implementation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-27
      • 2014-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多