f 字符串与 str.format()
- 2025-01-20 09:07:00
- admin 原创
- 80
问题描述:
我在 Python 3.5 项目中大量使用了它.format()
,但是我担心它会在下一个 Python 版本中被弃用,因为出现了一种新的字符串文字 f 字符串。
>>> name = "Test"
>>> f"My app name is {name}."
'My app name is Test.'
格式化字符串功能是否会完全取代旧功能.format()
?从现在开始,在所有情况下都使用新样式会更好吗?
我理解它基于“简单胜过复杂”的理念。但是,性能问题呢?它们之间有什么区别吗?或者只是相同功能的简单外观?
解决方案 1:
我担心它会在下一个 Python 版本中被弃用
不要这样,str.format
似乎不会(也没有理由)很快离开,引入f
前缀字符串的 PEP 甚至在其摘要中指出:
本 PEP 不提议删除或弃用任何现有的字符串格式化机制。
引入格式化字符串是为了解决其他格式化字符串方法所存在的一些缺点;不要抛弃旧方法,并强迫天知道有多少项目在希望他们的代码适用于 Python 3.6+ 时使用 f 字符串。
至于它们的性能,我最初怀疑它们可能会更慢,但这种怀疑是错误的,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 存储库的主分支完成的;它们肯定会发生变化:
f-strings
作为一项新功能,可能会进行优化对 CPython 的优化可能会使其
.format
速度更快(例如,加速方法调用 1.2 倍)
但实际上,不要太担心速度,而要担心什么对您和其他人来说更具可读性。
在很多情况下,情况确实如此f-strings
,但有些情况下情况会format
更好。
解决方案 2:
为了在 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 存储快速 0 (一)
12 4 LOAD_FAST 0(一个)
6 格式值 0
8 返回值
没有任何
15 0 LOAD_CONST 1 ('{a}')
2 LOAD_ATTR 0(格式)
4 LOAD_CONST 2 ('测试')
6 LOAD_CONST 3 (('a',))
8 调用函数 1
10 返回值
没有任何
可以看出,f 字符串无需属性或函数调用即可处理格式,这会带来类型检查和内存开销。据此,timeit
性能提升了大约 3 倍(对于我的特定函数而言)
>>> timeit.timeit('f1()', '来自 __main__ 导入 f1', number=100000)
0.012325852433775708
>>> timeit.timeit('f2()', '来自 __main__ 导入 f2', number=100000)
0.036395029920726074
解决方案 3:
有一件事没有提到,这使得弃用旧技术成为不可能,那就是插值仅适用于字符串文字。这意味着,字符串在运行时渲染一次,并且模板不能与更新的变量一起再次使用。例如:
>>> 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
使用了。如果没有较旧的技术,许多用例将是不可能的。享受字符串插值,但它并不适用于每个用例,即您需要可重用模板的地方。
解决方案 4:
我怀疑 str.format() 是否会被弃用,因为这对现有项目来说将是一场噩梦。话虽如此...
string = f'This is a {object}'
比以下更容易阅读
string = 'This is a {}'.format(object)
所以我说尽可能使用 f 字符串。
解决方案 5:
如果你想继续支持 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
解决方案 6:
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
仅支持属性或索引访问