f 字符串与 str.format()

问题描述 投票:0回答:6

我在 Python 3.5 项目中经常使用

.format()
,但我担心它会在下一个 Python 版本中被弃用,因为 f 字符串(一种新的字符串文字)。

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

格式化字符串功能是否会完全取代旧的

.format()
?从现在开始,在所有情况下都使用新样式会更好吗?

我理解这是基于“简单胜于复杂”的理念。然而,性能问题又如何呢?他们之间有什么区别吗?或者只是相同功能的简单外观?

python python-3.x string-formatting string-interpolation f-string
6个回答
100
投票

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

别这样,

str.format
似乎不会(也没有理由)很快离开,引入
f
前缀字符串的 PEP 甚至在其摘要中声明

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

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


至于这些的性能,我最初怀疑它们可能会更慢的怀疑是错误的,f 弦似乎很容易胜过它们的

.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 存储库的 master 分支完成的;它们肯定会发生变化:

  • f-strings
    ,作为一个新功能,可能有可能的优化
  • 对 CPython 的优化可能会使
    .format
    更快(例如 加速方法调用 1.2x

但实际上,不要太担心速度,担心什么对你和其他人来说更容易阅读。

在许多情况下,这将是

f-strings
,但是 在某些情况下
format
更好。


39
投票

为了以 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 (a)

 12 4 LOAD_FAST 0 (a)
              6 格式值 0
              8 返回值
没有任何
 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 字符串在没有属性或函数调用的情况下处理格式化,这会强加类型检查和内存开销。根据

timeit
,这会带来大约 3 倍的性能增益(对于我的特定功能)

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

26
投票

没有提到的一件事是,插值仅适用于字符串文字,这使得旧技术的弃用变得不可能。这意味着,字符串在运行时渲染一次,并且模板无法再次与更新的变量一起使用。就像你想的那样:

>>> 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
。如果没有旧技术,许多用例都是不可能的。享受字符串插值,但它并不适用于所有用例,即需要可重用模板的地方。


5
投票

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

string = f'This is a {object}'

更容易阅读
string = 'This is a {}'.format(object)

所以我建议尽可能使用 f 弦。


1
投票

如果你想继续支持 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

0
投票

f-strings
str.format()
不具备的另一个能力是表达式评估:

>>> b = b'hello'
>>> f'b = 0x{b.hex()}'
'b = 0x68656c6c6f'
>>> 'b = 0x{.hex()}'.format(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'bytes' object has no attribute 'hex()'

str.format
仅支持属性或索引访问

© www.soinside.com 2019 - 2024. All rights reserved.