是一个字符串格式化程序,它从调用范围不良实践中抽取变量?

我有一些代码可以完成很多字符串格式化工作,通常我会按照以下代码结束代码:

"...".format(x=x, y=y, z=z, foo=foo, ...)

我试图将大量变量插入到大字符串中。

是否有一个很好的理由不写这样的函数,它使用inspect模块来查找要插入的变量?

import inspect

def interpolate(s):
    return s.format(**inspect.currentframe().f_back.f_locals)

def generateTheString(x):
    y = foo(x)
    z = x + y
    # more calculations go here
    return interpolate("{x}, {y}, {z}")

下面的代码是一个更简单和更安全的方法。 inspect.currentframe在python的所有实现中都不可用,所以当你的代码不是时,代码会中断。 在jython,ironpython或pypy下它可能不可用,因为它似乎是一个cpython的东西。 这使得你的代码更加便于移植。

print "{x}, {y}".format(**vars())

这个技术实际上是在Python教程的输入和输出章节中描述的

这也可以通过将表格作为关键字参数传递给'**'符号来完成。 这在与新的内置vars()函数结合时特别有用,它返回一个包含所有局部变量的字典。

也在inspect.currentframe的python文档中

CPython实现细节:该函数依赖于解释器中的Python堆栈框架支持,但不能保证在所有Python实现中都存在。 如果在没有Python堆栈帧支持的实现中运行,则此函数返回None。


更新: Python 3.6具有此功能(更强大的变体)内置:

x, y, z = range(3)
print(f"{x} {y + z}")
# -> 0 3

参见PEP 0498 - 文字串插值


它[手动解决方案]导致嵌套函数有些令人惊讶的行为:

from callerscope import format

def outer():
    def inner():
        nonlocal a
        try:
            print(format("{a} {b}"))
        except KeyError as e:
            assert e.args[0] == 'b'
        else:
            assert 0

    def inner_read_b():
        nonlocal a
        print(b) # read `b` from outer()
        try:
            print(format("{a} {b}"))
        except KeyError as e:
            assert 0
    a, b = "ab"
    inner()
    inner_read_b()

注意:同一个调用成功或失败,取决于是否在上面或下面提到了一个变量。

callerscope在哪里:

import inspect
from collections import ChainMap
from string import Formatter

def format(format_string, *args, _format=Formatter().vformat, **kwargs):
    caller_locals = inspect.currentframe().f_back.f_locals
    return _format(format_string, args, ChainMap(kwargs, caller_locals))

好老邮差具有功能_所做的正是这件事情:

def _(s):
    if s == '':
        return s
    assert s
    # Do translation of the given string into the current language, and do
    # Ping-string interpolation into the resulting string.
    #
    # This lets you write something like:
    #
    #     now = time.ctime(time.time())
    #     print _('The current time is: %(now)s')
    #
    # and have it Just Work.  Note that the lookup order for keys in the
    # original string is 1) locals dictionary, 2) globals dictionary.
    #
    # First, get the frame of the caller
    frame = sys._getframe(1)
    # A `safe' dictionary is used so we won't get an exception if there's a
    # missing key in the dictionary.
    dict = SafeDict(frame.f_globals.copy())
    dict.update(frame.f_locals)
    # Translate the string, then interpolate into it.
    return _translation.gettext(s) % dict

所以如果巴里华沙能做到这一点,为什么我们不能?

链接地址: http://www.djcxy.com/p/76403.html

上一篇: Is a string formatter that pulls variables from its calling scope bad practice?

下一篇: How are Controllers used with MVC in Extjs application