我已经从Python Github存储库下载了Python 3.6 alpha版本,而我最喜欢的新功能之一就是文字字符串格式。可以这样使用:
>>> x = 2
>>> f"x is {x}"
"x is 2"
这似乎与在
format
实例上使用str
函数具有相同的作用。但是,我注意到的一件事是,与仅调用format
相比,这种文字字符串格式化实际上非常慢。这是timeit
关于每种方法的说明:>>> x = 2
>>> timeit.timeit(lambda: f"X is {x}")
0.8658502227130764
>>> timeit.timeit(lambda: "X is {}".format(x))
0.5500578542015617
如果我使用字符串作为
timeit
的参数,我的结果仍然显示该模式:>>> timeit.timeit('x = 2; f"X is {x}"')
0.5786435347381484
>>> timeit.timeit('x = 2; "X is {}".format(x)')
0.4145195760771685
如您所见,使用
format
将花费几乎一半的时间。我希望文字方法会更快,因为所涉及的语法更少。幕后发生了什么,导致原义方法变慢了很多? 最佳答案
注意:此答案是为Python 3.6 alpha版本编写的。 new opcode added to 3.6.0b1显着改善了f弦的性能。f"..."
语法在str.join()
表达式周围的文字字符串部分上有效地转换为{...}
操作,表达式本身的结果通过object.__format__()
方法传递(传递了任何:..
格式规范)。拆卸时可以看到以下内容:
>>> import dis
>>> dis.dis(compile('f"X is {x}"', '', 'exec'))
1 0 LOAD_CONST 0 ('')
3 LOAD_ATTR 0 (join)
6 LOAD_CONST 1 ('X is ')
9 LOAD_NAME 1 (x)
12 FORMAT_VALUE 0
15 BUILD_LIST 2
18 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
21 POP_TOP
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
>>> dis.dis(compile('"X is {}".format(x)', '', 'exec'))
1 0 LOAD_CONST 0 ('X is {}')
3 LOAD_ATTR 0 (format)
6 LOAD_NAME 1 (x)
9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
12 POP_TOP
13 LOAD_CONST 1 (None)
16 RETURN_VALUE
注意该结果中的
BUILD_LIST
和LOAD_ATTR .. (join)
操作码。新的FORMAT_VALUE
占据堆栈的顶部,再加上一个格式值(在编译时解析),以将它们合并到object.__format__()
调用中。因此,您的示例
f"X is {x}"
转换为:''.join(["X is ", x.__format__('')])
请注意,这需要Python创建一个列表对象,并调用
str.join()
方法。str.format()
调用也是方法调用,并且在解析后仍然涉及对x.__format__('')
的调用,但是至关重要的是,这里不涉及列表创建。正是这种差异使str.format()
方法更快。请注意,Python 3.6仅作为Alpha版本发布。此实现仍可以轻松更改。有关时间表,请参见PEP 494 – Python 3.6 Release Schedule;有关如何进一步提高格式化字符串文字的性能的讨论,请参见Python issue #27078(针对此问题而打开)。