首页 > 解决方案 > 在变量中的python字符串上触发f-string解析

问题描述

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

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

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

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

"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,但我仍然想知道最初的问题:给定sand d,您如何强制f'string'解析s?我在大括号内添加了另一个带有函数的示例,它.format也无法处理并且f'string'能够解决。

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

标签: pythonpython-3.xstringstring-formattingf-string

解决方案


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

"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 最支持的)不太一样。

格式字符串语法文档

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

表单的 [A]n 表达式'[index]'使用__getitem__()

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

如果您必须支持任意表达式,就像 f 字符串一样,并且您不从不受信任的来源获取模板字符串(这部分很重要),那么您可以解析出字段名称组件,然后使用该eval()函数来评估值在您输出最终字符串之前:

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()),但以上内容可能会让您更好地控制您可能想要支持的表达式。


推荐阅读