在变量中的 python 字符串上触发 f 字符串解析

Trigger f-string parse on python string in variable

这个问题来自处理jupyter magics,但可以用更简单的方式表达。给定一个字符串 s = "the key is {d['key']}" 和一个字典 d = {'key': 'val'},我们要解析该字符串。

旧方法是 .format(),这会引发错误 - 它不处理字典键。

"the key is {d['key']}".format(d=d)  # ERROR

我认为唯一的解决方法是将字典转换为对象(here 或此处解释)。

"the key is {d.key}".format(obj(d))

但是 Martijn 很好地解释了您可以简单地省略引号以使其正常工作:

"the key is {d[key]}".format(d=d)

新方法 f'string' 仍然以一种直观的 python 方式处理字典键:

f"the key is {d['key']}"

它还处理函数 - .format 也无法处理。

f"this means {d['key'].lower()}"

虽然我们现在知道你 可以 .format 来做,但我仍然想知道原来的问题:给定 sd,如何强制 f'string' 解析 s?我在大括号内添加了另一个带有函数的示例,.format 也无法处理,而 f'string' 将能够解决。

有什么功能.fstring()或方法可用吗? Python 内部使用什么?

字符串格式可以处理大多数字符串字典键很好,但您需要删除引号:

"the key is {d[key]}".format(d=d)

演示:

>>> d = {'key': 'val'}
>>> "the key is {d[key]}".format(d=d)
'the key is val'

str.format() 语法与 Python 表达式语法(这是 f-strings 主要支持的语法)不太一样。

来自Format String Syntax documentation

field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
[...]
element_index     ::=  digit+ | index_string
index_string      ::=  <any source character except "]"> +

[A]n expression of the form '[index]' does an index lookup using __getitem__()

语法是有限的,因为它会将任何纯数字字符串转换为整数,而其他所有内容始终被解释为字符串(尽管您可以使用嵌套的 {} 占位符动态插入键来自另一个变量的值)。

如果您必须支持任意表达式,就像 f-strings 一样,并且您不要从不受信任的来源获取模板字符串 (这部分很重要),然后您可以 parse out the field name components and then use the eval() function 在输出最终字符串之前评估这些值:

from string import Formatter

_conversions = {'a': ascii, 'r': repr, 's': str}

def evaluate_template_expressions(template, globals_=None):
    if globals_ is None:
        globals_ = globals()
    result = []
    parts = Formatter().parse(template)
    for literal_text, field_name, format_spec, conversion in parts:
        if literal_text:
            result.append(literal_text)
        if not field_name:
            continue
        value = eval(field_name, globals_)
        if conversion:
            value = _conversions[conversion](value)
        if format_spec:
            value = format(value, format_spec)
        result.append(value)
    return ''.join(result)

现在接受报价:

>>> s = "the key is {d['key']}"
>>> d = {'key': 'val'}
>>> evaluate_template_expressions(s)
'the key is val'

基本上,您可以对 eval(f'f{s!r}', globals()) 执行相同的操作,但以上内容可能会让您更好地控制您可能想要支持的表达式。

[G]iven s and d, how do you force a f'string' parse of s? Is there some function or method available?

这可以使用 eval 来完成...。 But beware eval!

>>> eval('f' + repr(s))
the key is val

repr 用于转义任何引号并用引号将 s 自身包裹起来。

如果您知道要格式化哪些变量(在本例中为 d),请选择 而不是 str.format。由于 eval.

的危险,上述解决方案应该是你最后的选择