Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 以字符串格式捕获**vars()模式_Python_Scope_String Formatting - Fatal编程技术网

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模块。这还不错,但如果我要经历创建函数的麻烦,我不会每次都要求调用方传递相同的东西,特别是如果有更好的方法的话。