为什么在Python 3.6 alpha中文字格式的字符串(f-strings)这么慢? (现在已在3.6稳定版中修复) [英] Why were literal formatted strings (f-strings) so slow in Python 3.6 alpha? (now fixed in 3.6 stable)

查看:119
本文介绍了为什么在Python 3.6 alpha中文字格式的字符串(f-strings)这么慢? (现在已在3.6稳定版中修复)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经从Python Github存储库下载了Python 3.6 alpha版本,我最喜欢的新功能之一是文字字符串格式.可以这样使用:

I've downloaded a Python 3.6 alpha build from the Python Github repository, and one of my favourite new features is literal string formatting. It can be used like so:

>>> x = 2
>>> f"x is {x}"
"x is 2"

这似乎与在str实例上使用format函数的作用相同.但是,我注意到的一件事是,与仅调用format相比,这种文字字符串格式化实际上非常慢.这是timeit关于每种方法的说明:

This appears to do the same thing as using the format function on a str instance. However, one thing that I've noticed is that this literal string formatting is actually very slow compared to just calling format. Here's what timeit says about each method:

>>> x = 2
>>> timeit.timeit(lambda: f"X is {x}")
0.8658502227130764
>>> timeit.timeit(lambda: "X is {}".format(x))
0.5500578542015617

如果我使用字符串作为timeit的参数,我的结果仍然显示该模式:

If I use a string as timeit's argument, my results are still showing the pattern:

>>> timeit.timeit('x = 2; f"X is {x}"')
0.5786435347381484
>>> timeit.timeit('x = 2; "X is {}".format(x)')
0.4145195760771685

如您所见,使用format几乎要花费一半的时间.我希望文字方法会更快,因为所涉及的语法更少.幕后发生了什么,导致文字方法的运行速度慢得多?

As you can see, using format takes almost half the time. I would expect the literal method to be faster because less syntax is involved. What is going on behind the scenes which causes the literal method to be so much slower?

推荐答案

注意:此答案是为Python 3.6 alpha版本编写的. 新的操作码已添加到3.6.0b1 中,大大改善了f字符串的性能.

Note: This answer was written for the Python 3.6 alpha releases. A new opcode added to 3.6.0b1 improved f-string performance significantly.

对于在{...}表达式周围的文字字符串部分,f"..."语法有效地转换为str.join()操作,并且表达式本身的结果通过object.__format__()方法传递(传递任何:..格式)规范中).拆卸时可以看到以下内容:

The f"..." syntax is effectively converted to a str.join() operation on the literal string parts around the {...} expressions, and the results of the expressions themselves passed through the object.__format__() method (passing any :.. format specification in). You can see this when disassembling:

>>> 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_LISTLOAD_ATTR .. (join)操作码.新的FORMAT_VALUE占据堆栈的顶部,再加上一个格式值(在编译时解析),以将它们组合成一个object.__format__()调用.

Note the BUILD_LIST and LOAD_ATTR .. (join) op-codes in that result. The new FORMAT_VALUE takes the top of the stack plus a format value (parsed out at compile time) to combine these in a object.__format__() call.

因此,您的示例f"X is {x}"被翻译为:

So your example, f"X is {x}", is translated to:

''.join(["X is ", x.__format__('')])

请注意,这需要Python创建一个列表对象,然后调用str.join()方法.

Note that this requires Python to create a list object, and call the str.join() method.

str.format()调用也是方法调用,并且在解析之后仍然涉及对x.__format__('')的调用,但是至关重要的是,这里没有涉及 list创建.正是这种差异使str.format()方法更快.

The str.format() call is also a method call, and after parsing there is still a call to x.__format__('') involved, but crucially, there is no list creation involved here. It is this difference that makes the str.format() method faster.

请注意,Python 3.6仅作为Alpha版本发布.此实现仍可以轻松更改.请参阅 PEP 494 – Python 3.6发布时间表 时间表以及 Python问题#27078 (针对此问题而打开)的讨论如何进一步提高格式化的字符串文字的性能.

Note that Python 3.6 has only been released as an alpha build; this implementation can still easily change. See PEP 494 – Python 3.6 Release Schedule for the time table, as well as Python issue #27078 (opened in response to this question) for a discussion on how to further improve the performance of formatted string literals.

这篇关于为什么在Python 3.6 alpha中文字格式的字符串(f-strings)这么慢? (现在已在3.6稳定版中修复)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆