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

发布于 2024-08-20 10:59:41 字数 738 浏览 7 评论 0原文

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

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

I frequently find myself using the following pattern for 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()))

That is, I often have the values I need to print in the local namespace, represented by a call to vars(). As I look over my code, however, it seems awfully unpythonic to be constantly repeating the .format(**vars()) pattern.

I'd like to create a function that will capture this pattern. It would be something like the following.

# 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())

Except that by the time I'm in the lfmt namespace, vars() is no longer what I want.

How can I write lfmt so that it executes vars() in the caller's namespace such that the following code would work as the example above?

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鹤仙姿 2024-08-27 10:59:41

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

Edit: In order for lfmt to work when called from different namespaces, you'll need the inspect module. Note, as the documentation warns, the inspect module may not be suitable for production code since it may not work with all implementations of 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
失而复得 2024-08-27 10:59:41

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

这将帮助您开始:

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

You have to inspect the variables from the calling frames.

This will get you started:

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')
零度℉ 2024-08-27 10:59:41

在这里:

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

Here you are:

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}")

The fact that it works doesn't mean you should use it. This is what developers call "major hack", usually shipped with a comment "XXX fix me XXX".

沒落の蓅哖 2024-08-27 10:59:41

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

Is it so bad to type ,vars each time you call the function?

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))
甜妞爱困 2024-08-27 10:59:41

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

import sys

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

据我所知: Python 字符串插值实现

You could also use sys instead of inspect, but I don't know if it has the same problem with different implementations as inspect has.

import sys

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

This is as far as I got: Python string interpolation implementation

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文