是一个字符串格式化程序,从其调用范围的不良做法中提取变量?

Eri*_*ric 10 python

我有一些代码可以执行大量的字符串格式化.通常,我最终得到的代码如下:

"...".format(x=x, y=y, z=z, foo=foo, ...)
Run Code Online (Sandbox Code Playgroud)

我试图将大量变量插入到一个大字符串中.

是否有充分的理由不编写这样的函数来使用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}")
Run Code Online (Sandbox Code Playgroud)

Mar*_*agh 8

一种更简单,更安全的方法是下面的代码.inspect.currentframe在python的所有实现上都不可用,所以当你的代码没有时,你的代码就会中断.在jython,ironpython或pypy下它可能不可用,因为它似乎是一个cpython的东西.这使您的代码不那么便携.

print "{x}, {y}".format(**vars())
Run Code Online (Sandbox Code Playgroud)

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

这也可以通过将表作为关键字参数传递'**'表示法来完成.这与新的内置vars()函数结合使用时特别有用,该函数返回包含所有局部变量的字典.

也在inspect.currentframe的python文档中

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


jfs*_*jfs 8

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

x, y, z = range(3)
print(f"{x} {y + z}")
# -> 0 3
Run Code Online (Sandbox Code Playgroud)

参见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()
Run Code Online (Sandbox Code Playgroud)

注意:同一个调用成功或失败取决于是否在其上方或下方提到变量.

在哪里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))
Run Code Online (Sandbox Code Playgroud)