如何推迟/延迟 f 字符串的评估?

新手上路,请多包涵

我正在使用模板字符串生成一些文件,我喜欢为此目的使用新的 f 字符串的简洁性,因为它减少了我以前的模板代码,如下所示:

 template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
    print (template_a.format(**locals()))

现在我可以这样做了,直接替换变量:

 names = ["foo", "bar"]
for name in names:
    print (f"The current name is {name}")

然而,有时在别处定义模板是有意义的——在代码的更高层,或者从文件或其他东西导入。这意味着模板是一个带有格式化标签的静态字符串。字符串必须发生某些事情才能告诉解释器将字符串解释为新的 f 字符串,但我不知道是否存在这样的事情。

有什么方法可以引入字符串并将其解释为 f 字符串以避免使用 .format(**locals()) 调用?

理想情况下,我希望能够像这样编写代码……(其中 magic_fstring_function 是我不理解的部分所在):

 template_a = f"The current name is {name}"
# OR [Ideal2] template_a = magic_fstring_function(open('template.txt').read())
names = ["foo", "bar"]
for name in names:
    print (template_a)

…有了这个所需的输出(无需两次读取文件):

 The current name is foo
The current name is bar

…但我得到的实际输出是:

 The current name is {name}
The current name is {name}

原文由 JDAnders 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 670
2 个回答

这是一个完整的“理想2”。

它不是 f 弦——它甚至不使用 f 弦——但它会按要求使用。完全按照指定的语法。没有安全问题,因为我们没有使用 eval()

它使用一个小类并实现 __str__ 由打印自动调用。为了摆脱类的有限范围,我们使用 inspect 模块向上跳一帧并查看调用者有权访问的变量。

 import inspect

class magic_fstring_function:
    def __init__(self, payload):
        self.payload = payload
    def __str__(self):
        vars = inspect.currentframe().f_back.f_globals.copy()
        vars.update(inspect.currentframe().f_back.f_locals)
        return self.payload.format(**vars)

template = "The current name is {name}"

template_a = magic_fstring_function(template)

# use it inside a function to demonstrate it gets the scoping right
def new_scope():
    names = ["foo", "bar"]
    for name in names:
        print(template_a)

new_scope()
# The current name is foo
# The current name is bar

原文由 Paul Panzer 发布,翻译遵循 CC BY-SA 4.0 许可协议

将字符串评估为 f 字符串(具有其全部功能)的简洁方法是使用以下函数:

 def fstr(template):
    return eval(f"f'{template}'")

然后你可以这样做:

 template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
    print(fstr(template_a))
# The current name is foo
# The current name is bar

而且,与许多其他建议的解决方案相比,您还可以:

 template_b = "The current name is {name.upper() * 2}"
for name in names:
    print(fstr(template_b))
# The current name is FOOFOO
# The current name is BARBAR

原文由 kadee 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题