【问题标题】:How do I convert a string into an f-string?如何将字符串转换为 f 字符串?
【发布时间】:2018-04-30 13:12:05
【问题描述】:

我在 python 的新 f-strings 上阅读了这个blog,它们看起来非常整洁。但是,我希望能够从字符串或文件中加载 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'

【问题讨论】:

  • s.format(name="John", age=10)s.format(**globals) 或类似的。
  • f-strings 是 python 3.6 中的新内容,是不可调用的文字。我知道如何获得类似的东西。我想要的是制作一个现有的字符串(可能从文件中加载)并让它成为一个格式化的字符串文字。
  • 所以如果我理解正确,你问如何控制 f 字符串中的表达式何时被评估,@piRSquared?
  • 给自己一个nice read :)
  • IIUC,不幸的是,除非您使用exec :((至少,我认为是这样)

标签: python python-3.x string-interpolation f-string


【解决方案1】:

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

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

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

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

如果你想从一个文件中加载 f-string f"My name is {name} and I am {age} years old",那么实际放

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 字符串的来源。

【讨论】:

  • 我不太明白为什么有人会使用 compile 和 eval 而不是 string_from_file.format(**locals())。如果答案是“因为 f 字符串可以有更复杂的表达式”,那么编写一个处理所有必需表达式的小型 DSL 似乎比使用 eval 并允许任意代码执行更可取。
  • @l4mpi 你能举个例子吗?我正面临这个问题,并想以你的方式尝试(我的后备是像 Jinja 这样的模板引擎)
  • @stevepastelan 基本上我推荐str.format 方法而不是f-strings。对于此答案中的 f 字符串 myStr=f"my name is {name} and I'm {age} years old",您只需删除前导 f 并使用 myString.format(name=&lt;namevalue&gt;, age=&lt;agevalue&gt;) 即可获得格式化的输出。如果您想从作用域中获取占位符值而不是单独传递它们,请使用myStr.format(**locals()) 将所有本地变量传递给format。当然,这不适用于 f 字符串中的表达式(例如 {age+1}),所以如果你需要它们,你必须自己处理它们......
  • @stevepastelan 表达式是 DSL 等发挥作用的地方。例如。如果您需要支持加法和三元 if 运算符,您可以为格式字符串创建合适的语法,相应地解析字符串(手动或使用例如 ANTLR),然后编写一个小类来处理评估表达式和创建输出。当然,如果你需要支持复杂的表达式,你最好使用现有的模板引擎,或者只使用 f-strings,但对于生产代码,我需要非常有说服力的理由来使用任何允许任意代码执行的东西。跨度>
【解决方案2】:

一个简单的解决方案是使用 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 可能很危险,但如果你知道你的来源,那么我认为它并不比执行任何其他代码更危险。

【讨论】:

  • 我真诚地希望没有人使用不受信任的输入来执行此操作:P
  • 非常非常整洁。但当然也很危险。
【解决方案3】:

但是如果我有一个字符串 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当然,除非你愿意使用@coldspeed 提到的exec 之类的东西。但到那时,可能弊大于利。

【讨论】:

  • 我认为他正在寻找一些函数foo 使得foo("{x}") 返回f"{x}"
  • @PatrickHaugh 啊,我明白你的意思了。完全搞不懂他在问什么。我会删除我的答案。
  • 我暂时不接受。如果将来发生变化,我会更新这篇文章。
  • @ChristianDean 我不接受,因为一旦我开始工作,我预计会接受另一个答案。再次感谢您的回答。
  • @piRSquared 嘿伙计,没问题。我很感激你让我知道。如果你确实让它工作,也许你可以在这里回复一个答案。我相信其他人会感兴趣,包括我自己:)
猜你喜欢
  • 2017-11-29
  • 1970-01-01
  • 2012-05-16
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 2019-01-05
相关资源
最近更新 更多