45

我正在阅读有关 python 的新 f-strings 的博客,它们看起来非常整洁。但是,我希望能够从字符串或文件中加载 f 字符串。

我似乎找不到任何执行此操作的字符串方法或其他函数。

从我上面链接中的示例:

name = 'Fred'
age = 42
f"My name is {name} and I am {age} years old"

'My name is Fred and I am 42 years old'

但是如果我有一个字符串s呢?我希望能够 eff-ify s,像这样:

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)

事实证明,我已经可以执行类似的操作str.format并获得性能提升。即:

format = lambda name, age: f"My name is {name} and I am {age} years old"
format('Ted', 12)

'My name is Ted and I am 12 years old'
4

3 回答 3

28

f 字符串是代码。不仅以安全的“字符串文字当然是代码”的方式,而且以危险的任意代码执行方式。这是一个有效的 f 字符串:

f"{__import__('os').system('install ransomware or something')}"

它会在评估时执行任意 shell 命令。

您正在询问如何获取从文本文件加载的字符串并将其评估为代码,答案归结为eval. 这当然是一个安全风险并且可能是个坏主意,所以我建议不要尝试从文件中加载 f 字符串。

如果你想f"My name is {name} and I am {age} years old"从文件中加载 f 字符串,那么实际上把

f"My name is {name} and I am {age} years old"

在文件中,f以及引号和所有。

从文件中读取,编译并保存(因此eval不必每次都重新编译):

compiled_fstring = compile(fstring_from_file, '<fstring_from_file>', 'eval')

并评估它eval

formatted_output = eval(compiled_fstring)

如果您这样做,请非常小心您加载 f 字符串的来源。

于 2017-12-01T18:17:12.623 回答
21

一个简单的解决方案是使用 f-strings 和 eval。

def effify(non_f_str: str):
    return eval(f'f"""{non_f_str}"""')

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)
'My name is Fred and I am 42 years old'

这基本上是在字符串前面加上一个“f”,然后作为代码计算。三重引号也有助于容纳多行字符串。该函数将尝试从其调用周围的范围中提取 f 字符串中引用的变量。正如所指出的,使用eval可能是危险的,但如果你知道你的来源,那么我认为它并不比执行任何其他代码更危险。

于 2019-01-07T09:19:44.197 回答
9

但是如果我有一个字符串 s 呢?我希望能够 eff-ify s,像这样:

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)

AFAIU,根据PEP 498 - Literal String Interpolation,这是不可能的1。无法以编程方式创建 f 字符串:

在 Python 源代码中,f-string 是一个以 'f' 为前缀的文字字符串,其中包含大括号内的表达式


1当然,除非您愿意使用exec@coldspeed 提到的东西。但在这一点上,缺点可能超过优点。

于 2017-11-16T21:22:24.407 回答