Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 嵌套字符串文字插值是否可行?_Python_String_Python 3.6 - Fatal编程技术网

Python 嵌套字符串文字插值是否可行?

Python 嵌套字符串文字插值是否可行?,python,string,python-3.6,Python,String,Python 3.6,使用时,在某种程度上可以嵌套f字符串 a = 3 b = 7 res = f"{f'{a*b}'}" print(res) # '21' 但是,如果内部表达式是包含字符串的变量,则同样的方法不起作用 a = 3 b = 7 expr = 'a*b' res = f"{f'{expr}'}" print(res) # 'a*b' 有没有一种方法可以使这项功能正常工作,并使第二个输出也成为'21'?如果没有,第一个字符串和第二个字符串之间的区别是什么?有一些库已经开发了安全评估数字和逻

使用时,在某种程度上可以嵌套f字符串

a = 3
b = 7

res = f"{f'{a*b}'}"

print(res) # '21'
但是,如果内部表达式是包含字符串的变量,则同样的方法不起作用

a = 3
b = 7

expr = 'a*b'

res = f"{f'{expr}'}"

print(res) # 'a*b'

有没有一种方法可以使这项功能正常工作,并使第二个输出也成为
'21'
?如果没有,第一个字符串和第二个字符串之间的区别是什么?

有一些库已经开发了安全评估数字和逻辑表达式的函数(“安全”是关键)

首先,设置-

a = 3
b = 7
op = '*'
numexpr.evaluate
它足够聪明,可以优化您的表情,在某些情况下甚至比numpy更快。使用
pip
安装


pandas.eval
API的安全评估类似于
ne.evaluate

>>> import pandas as pd
>>> pd.eval(f'{a} {op} {c}')
12

我认为,当调用这些表达式时,查看引擎盖下实际发生的情况会有所帮助

f“{f'{a*b}}”
外部f字符串遇到一个它计算的表达式,而内部f字符串也找到一个它计算的表达式,这导致调用
BINARY\u MULTIPLY

f“{f'{expr}}”
这里,第一个f-string遇到表达式并对其求值,而内部f-string遇到字符串,导致调用
LOAD\u FAST
,而不是将字符串的内容作为Python代码求值

同样重要的是,在第二个示例中,要注意第一个示例中出现的对
a
b
LOAD\u FAST
调用缺失。

它被称为“字符串文字插值”。字符串必须是文本,即编译时,编译器会将字符串转换为正确的可执行代码。如果您已经有一个字符串作为值(而不是文字),那么就太晚了

我无法访问启用了PEP 498的Python,因此我的示例将使用Ruby,Ruby已经使用这种机制很长时间了。Python的
f“…{expr}…”
的Ruby语法是
“…{expr}…”

在Ruby中,
“a#{2*3}b”
[“a”,(2*3),“b”]的语法糖。如果字符串
“2*3”
已经作为值存在,编译器将无法对其执行任何操作;将字符串值转换为结果的唯一方法是对其求值

在第一个示例中,在字符串文本中有一个字符串文本;这两者都由编译器在编译时处理:当编译器看到外部文本时,它编译它,在那里找到另一个字符串文本,也编译它,生成代码。事实上,
“a{”{2*3}}b”
同样产生完全相同的字节码

这是在编译时完成的,这也是为什么字符串文字插值会在表达式格式错误时引发语法错误的原因,即使所讨论的行从未执行过:
if false;"#{1+}"; 结束
将产生一个
语法错误


这是在编译时完成的,这意味着变量中已经存在的字符串不符合此机制的条件。在代码中,在计算
res
时,
expr
可能是任何东西;唯一的出路是
evil
(或者另一个更安全的评估者)。

只是为了澄清一下,你想知道你是否可以让第二个输出21?也许你可以在里面放一个
eval
,即
res=f“{f'{eval(expr)}”
如果有人用eval发布答案,他们会被否决。@user3483203我跟你打赌,给你两个选项有些关联:10分钟前不是你在一个问题上发誓要用eval否决任何东西吗?@OlivierMelançon builtin
eval
,是的。我仍然认为这是公平的,我更感兴趣的是知道为什么不能用f字串,如果它真的不能,但你的答案很有趣。为什么pandas.eval被认为是安全的?@OlivierMelançon为什么不起作用?我不确定,但我可以回答第二个问题
pandas.eval
实际上有代码来解析它接收到的表达式,并且它对它认为有效和无效的操作的类型非常严格。例如,将语句导入到
pd.eval
是一个严格的禁忌。最好显示字节码。这个答案确实很有帮助,但如果不是因为@Amadan answer中给出的关键事实,即f字符串代码是在编译时生成的,而不是在运行时生成的,并且它不依赖于调用eval,那么这个答案就不够了。如果我能接受这两个答案,我希望他们能给出最好的解释。
>>> import pandas as pd
>>> pd.eval(f'{a} {op} {c}')
12
def om1(a, b):
    return f"{f'{a*b}'}"

dis.dis(om1)
  2           0 LOAD_FAST                0 (a)
              2 LOAD_FAST                1 (b)
              4 BINARY_MULTIPLY
              6 FORMAT_VALUE             0
              8 FORMAT_VALUE             0
             10 RETURN_VALUE
def om2(a, b):
    expr = 'a*b'
    return f"{f'{expr}'}"

dis.dis(om2)
  2           0 LOAD_CONST               1 ('a*b')
              2 STORE_FAST               2 (expr)

  3           4 LOAD_FAST                2 (expr)
              6 FORMAT_VALUE             0
              8 FORMAT_VALUE             0
             10 RETURN_VALUE