python - 为什么在 Python 3.6 alpha 中文字格式的字符串(f 字符串)如此缓慢? (现在在 3.6 稳定版中修复)

标签 python performance python-internals python-3.6 f-string

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

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

这似乎与在 str 实例上使用 format 函数的作用相同。但是,我注意到的一件事是,与仅调用 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-string 的性能。


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_LISTLOAD_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 (针对这个问题打开)讨论如何进一步提高格式化字符串文字的性能。

关于python - 为什么在 Python 3.6 alpha 中文字格式的字符串(f 字符串)如此缓慢? (现在在 3.6 稳定版中修复),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37365311/

相关文章:

python - Werkzeug 响应太慢

python - 使用参数启动 pytest fixture

performance - 推荐系统 - Recall@K 和 Precision@K

python - 线程和 Django 数据库创建操作

python - 使用 numpy 连接 2 个列表

mysql - 如何加速MySQL查询: order by count

java - 处理批处理记录后如何提交kafka offset

python - 为什么字符串乘法的字节码不同?

python - 为什么list()和[]之间的getsizeof结果不同?

python - 在哪里可以找到 os.urandom() 的源代码?