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

Roe*_*ant 1 python string string-formatting python-3.x f-string

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

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

"the key is {d['key']}".format(d=d)  # ERROR
Run Code Online (Sandbox Code Playgroud)

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

"the key is {d.key}".format(obj(d))
Run Code Online (Sandbox Code Playgroud)

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

"the key is {d[key]}".format(d=d)
Run Code Online (Sandbox Code Playgroud)

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

f"the key is {d['key']}"
Run Code Online (Sandbox Code Playgroud)

它还处理功能——某些东西.format也无法处理。

f"this means {d['key'].lower()}"
Run Code Online (Sandbox Code Playgroud)

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

是否有一些功能.fstring()或方法可用?Python 内部使用什么?

Mar*_*ers 6

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

"the key is {d[key]}".format(d=d)
Run Code Online (Sandbox Code Playgroud)

演示:

>>> d = {'key': 'val'}
>>> "the key is {d[key]}".format(d=d)
'the key is val'
Run Code Online (Sandbox Code Playgroud)

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

格式字符串语法文档

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

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

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

如果您必须支持任意表达式,就像 f-strings 一样,并且您不从不受信任的来源获取模板字符串(这部分很重要),那么您可以解析字段名称组件,然后使用该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)
Run Code Online (Sandbox Code Playgroud)

现在接受报价:

>>> s = "the key is {d['key']}"
>>> d = {'key': 'val'}
>>> evaluate_template_expressions(s)
'the key is val'
Run Code Online (Sandbox Code Playgroud)

本质上,您可以使用 做同样的事情eval(f'f{s!r}', globals()),但上面的内容可能会让您更好地控制您可能想要支持的表达式。