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

Dav*_*ete 8 python python-3.x python-internals python-3.6 f-string

我正在玩f字符串(请参阅PEP 498),因此我决定检查f字符串解析(例如f“ {1}”)的速度与通常的str解析(例如str(1) ))。但是令我惊讶的是,当我使用timeit函数检查两种方法的速度时,我发现

>>> from timeit import timeit
>>> timeit("f'{1}'")
0.1678762999999961
Run Code Online (Sandbox Code Playgroud)

>>> timeit("str(1)")
0.3216999999999999
Run Code Online (Sandbox Code Playgroud)

甚至是repr func,在大多数情况下,它们都比str转换快

>>> timeit("repr(1)")
0.2528296999999995
Run Code Online (Sandbox Code Playgroud)

我不知道为什么呢?我以为f弦在内部调用了str,但是现在,我有点困惑了,有什么想法吗?提前致谢!

PD:就像有人想知道的那样:

assert f"{1}" == str(1) == repr(1)
Run Code Online (Sandbox Code Playgroud)

cs9*_*s95 14

简单的答案是因为f字符串是该语言的语法和语法的一部分。str()另一方面,该调用需要符号表查找,然后是函数调用。

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

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)
Run Code Online (Sandbox Code Playgroud)

当您使用来查看反汇编的字节码时,行为上的差异是显而易见的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
Run Code Online (Sandbox Code Playgroud)

繁重的工作全部在CALL_FUNCTION指令中,f字符串当然没有这些开销-至少在这种情况下,因为不需要执行任何操作eval