为什么 f 字符串比 str() 解析值更快?

Why are f-strings faster than str() to parse values?

我在玩 f-strings(见 PEP 498), and I decided to check the speed of the f-string parse, (e.g. f"{1}") in comparison with the usual str parse (e.g str(1)). But to my surprise, when I checked the speed of both methods with the timeit 函数,我发现 f 弦更快。

>>> from timeit import timeit
>>> timeit("f'{1}'")
0.1678762999999961

>>> timeit("str(1)")
0.3216999999999999

甚至是 repr func,在大多数情况下它比 str cast

>>> timeit("repr(1)")
0.2528296999999995

我想知道这是为什么?我认为 f 弦在内部称为 str,但现在,我有点困惑,有什么想法吗?提前致谢!

PD:如果有人想知道:

assert f"{1}" == str(1) == repr(1)

简单的答案是因为 f-strings are part of the language's grammar and syntax. 另一方面,str() 调用需要符号 table 查找,然后是函数调用。

下面是一个对整数变量进行插值的类似示例,将其与常量值插值进行对比。

x = 1

%timeit f'{1}'
%timeit f'{x}'
%timeit str(1)
%timeit str(x)

113 ns ± 2.25 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
166 ns ± 4.71 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
342 ns ± 23.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
375 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

当您查看带有 dis.

的反汇编字节码时,行为的差异很明显
import dis

dis.dis("f'{x}'")
  1           0 LOAD_NAME                0 (x)
              2 FORMAT_VALUE             0
              4 RETURN_VALUE

dis.dis("str(x)")
  1           0 LOAD_NAME                0 (str)
              2 LOAD_NAME                1 (x)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE

繁重的工作都在 CALL_FUNCTION 指令中,这是 f-strings 肯定没有的开销——至少在这种情况下,因为不需要 eval 'd.