为什么在Python 3.6 alpha中文字格式的字符串(f-strings)这么慢?(现已在3.6稳定版中修复)

发布于 2021-01-29 15:17:56

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

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

这似乎与formatstr实例上使用该功能具有相同的作用。但是,我注意到的一件事是,与仅调用相比,这种文字字符串格式化实际上非常慢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几乎要花费一半的时间。我希望文字方法会更快,因为所涉及的语法更少。幕后发生了什么,导致文字方法的运行速度慢得多?

关注者
0
被浏览
48
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    注意 :此答案是为Python 3.6
    alpha版本编写的。一个新的操作码添加到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_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发布时间表

    ,以及有关如何进一步提高格式化字符串文字性能的讨论,请参见Python问题#27078(针对该问题而打开)。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看