如何使用 ast.literal_eval 计算 f 个字符串

How to evaluate f strings using ast.literal_eval

当尝试用 ast.literal_eval 评估 f 弦时,我得到一个 ValueError 关于 "malformed node or string":

from ast import literal_eval

a = 10

literal_eval("f'test {a}'")

抛出以下错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<...> in <module>()
      3 a = 10
      4 
----> 5 literal_eval("f'test {a}'")

C:\...\lib\ast.py in literal_eval(node_or_string)
     83                     return left - right
     84         raise ValueError('malformed node or string: ' + repr(node))
---> 85     return _convert(node_or_string)
     86 
     87 

C:\...\lib\ast.py in _convert(node)
     82                 else:
     83                     return left - right
---> 84         raise ValueError('malformed node or string: ' + repr(node))
     85     return _convert(node_or_string)
     86 

ValueError: malformed node or string: <_ast.JoinedStr object at 0x000001F20CE718D0>

但是它对原始或二进制字符串没有问题:

>>> literal_eval("r'This'")
'This'
>>> literal_eval("b'This'")
b'This'

我可以让 ast.literal_eval 在 F 弦上工作吗?如果是,我需要更改什么?

这是不可能的。 F 字符串类似于以下内容1 :

map = {}
map.update(globals())
map.update(locals())
string.format(**map)

这实际上是一种戏剧性的轻描淡写 -- f 字符串还支持其他类型的表达式,而不仅仅是名称查找或简单的东西,例如您可以使用普通格式字符串获得的项目访问。例如它们支持任何其他有效的 python 表达式,包括函数调用、数学方程式等。

>>> expr = '"boom"'
>>> f'foo{eval(expr)}'
'fooboom'

f 字符串使用 __format__ 协议求值,它包含的表达式使用普通 python 求值。这意味着 f 字符串 不能 是文字。这是一个表达式1。请注意,与任何任意表达式一样,它不能被安全地计算——因此您可能甚至不希望它成为 "eval-able" by ast.literal_eval 无论如何。

1在 AST 中,您会看到它是通过 JoinedStrStrFormattedValue ast 节点。其中,唯一可以被视为文字的是 Str.

F 字符串可以包含任意复杂的表达式。一个简单的例子。

>>> a = 2; b=3; print(f'x{a**b}x')

x8x

它们既不是文字也不是文字,不适合 literal_eval。