【问题标题】:f-strings vs str.format()f-strings 与 str.format()
【发布时间】:2017-08-24 16:56:29
【问题描述】:

我在我的 Python 3.5 项目中经常使用 .format(),但我担心它会在下一个 Python 版本中被弃用,因为 f-strings 是一种新的字符串文字。

>>> name = "Test"
>>> f"My app name is {name}."
'My app name is Test.'

格式化字符串功能是否会完全取代旧的.format()?而且从现在开始,是不是所有情况都使用新样式比较好?

我知道这是基于“简单胜于复杂”的理念。但是,性能问题呢?它们之间有什么区别吗?还是只是相同功能的简单外观?

【问题讨论】:

  • 等一下,谁说.format()会贬值?我怀疑
  • 没有人,我同意。我想知道的事情之一.. 以备将来使用。
  • 在 Python 3 的初始版本发布后,社区清楚地了解到将破坏兼容性的更改引入新版本是多么痛苦,我认为他们不会再重复这个决定轻轻。也许当 Python 4 在 1983 年后问世...
  • @Kevin 谢谢。我希望如此。
  • 如果您想要完整版的功能背后的推理,可能值得阅读PEP 498

标签: python python-3.x string-formatting string-interpolation f-string


【解决方案1】:

我怀疑 str.format() 会被弃用,因为这对于现有项目来说将是一场噩梦。话说……

string = f'This is a {object}'

比阅读更容易

string = 'This is a {}'.format(object)

所以我说尽可能使用 f 字符串。

【讨论】:

    【解决方案2】:

    有一点没有提到,这使得旧技术不可能被弃用,那就是插值仅适用于字符串文字。意思是,字符串在运行时呈现一次,并且模板不能再次与更新的变量一起使用。比如你会:

    >>> str_template = '{i} squared: {n}'
    >>> for i in range(2, 5):
    ...     print(str_template.format(i=i, n=i**2))
    ... 
    2 squared: 4
    3 squared: 9
    4 squared: 16
    

    另一种情况是i18n,其中使用了string.Template。如果没有旧技术,许多用例将是不可能的。享受字符串插值,但它并不适用于所有用例,即需要可重用模板的地方。

    【讨论】:

      【解决方案3】:

      恐怕它会在下一个 Python 版本中被弃用

      不要,str.format 不会出现(也没有理由)很快就会离开,引入 fprefixed-strings 的 PEP 甚至 states in its Abstract

      本 PEP 不建议删除或弃用任何现有的字符串格式化机制。

      引入格式化字符串是为了解决其他格式化字符串方法的一些缺点;不要扔掉旧方法并强迫天知道有多少项目使用 f-string,如果他们希望他们的代码适用于 Python 3.6+。


      至于这些的性能,我最初怀疑它们可能会更慢似乎是错误的,f-strings 似乎很容易胜过它们的 .format 同行:

      ➜ cpython git:(master) ./python -m timeit -s "a = 'test'" "f'formatting a string {a}'"
      500000 loops, best of 5: 628 nsec per loop
      ➜ cpython git:(master) ./python -m timeit "'formatting a string {a}'.format(a='test')"
      100000 loops, best of 5: 2.03 usec per loop
      

      在撰写本文时,这些都是针对 CPython 存储库的主分支完成的;它们肯定会发生变化:

      • f-strings,作为一个新特性,可能会有优化
      • 对 CPython 的优化可能会使 .format 更快(例如 Speedup method calls 1.2x

      但是说真的,不要太担心速度,担心什么对你和其他人来说更易读。

      在许多情况下,这将是f-strings,但there's some cases 其中format 更好。

      【讨论】:

      • 性能改进怎么样?内部实现有什么不同吗?
      • @nivhanin 和 Jim,我做了一个简短的速度调查,但是浏览源代码会很有趣,我敢打赌,即使生成了字节码,他们实际上也会共享很多代码by dis 相对不同。如果我猜的话,随着字符串变得更长并且具有更复杂的格式规则,两者之间的差异会缩小。
      • @Aaron 好点。我想看看这里公布的结果;)
      • 我发现你的速度比较很有趣,因为它在我的机器上(来自 Anaconda 的 Python 3.6.2)有很大不同:fstring 版本需要 0.0845 微秒,而格式版本需要 0.555 微秒。所以当你看到一个因素〜3,我看到一个因素〜6。奇数。
      【解决方案4】:

      如果你想继续支持 python 3.5,你可以使用fstring

      pip install fstring

      from fstring import fstring
      
      x = 1
      
      y = 2.0
      
      plus_result = "3.0"
      
      print fstring("{x}+{y}={plus_result}")
      
      # Prints: 1+2.0=3.0
      

      【讨论】:

      • 改用.format不是更好吗?这个fstring 不是python 3.6 f-strings 的直接端口,不支持格式化
      【解决方案5】:

      为了基于 Jim 的回答并解决您的性能问题,我使用了 python 的 dis 模块来比较两个语法不同但功能相同的函数的字节码指令。

      import dis
      
      def f1():
          a = "test"
          return f"{a}"
      
      def f2():
          return "{a}".format(a='test')
      
      print(dis.dis(f1))
      print(dis.dis(f2))
      

      其中的结果是:

       11 0 LOAD_CONST 1 ('测试')
                    2 STORE_FAST 0 (一)
      
       12 4 加载快速 0 (一)
                    6 FORMAT_VALUE 0
                    8 RETURN_VALUE
      没有
       15 0 LOAD_CONST 1 ('{a}')
                    2 LOAD_ATTR 0(格式)
                    4 LOAD_CONST 2 ('测试')
                    6 LOAD_CONST 3 (('a',))
                    8 CALL_FUNCTION_KW 1
                   10 返回值
      无

      可以看出,f-string 处理格式化时没有属性或函数调用,这会增加类型检查和内存开销。根据timeit,这导致大约 3 倍的性能提升(对于我的特定功能)

      >>> timeit.timeit('f1()', 'from __main__ import f1', number=100000)
      0.012325852433775708
      >>> timeit.timeit('f2()', 'from __main__ import f2', number=100000)
      0.036395029920726074

      【讨论】:

      • @Aaron 这到底是做什么的?还;你如何从印刷文本中获取这些信息?
      • @Vicrobot dis 是反汇编的缩写。它采用编译函数的字节码,并将 python 虚拟机指令(二进制数据)解码为人类可读的单词。 python 虚拟机是stack based vm,所以所有的“LOAD”和“STORE”命令都是指从堆栈中推送和拉取数据。有关dis 库的更多信息,请访问here
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-16
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多