ChatGPT解决这个技术问题 Extra ChatGPT

我在我的 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 在 1,983 年后问世...
@凯文谢谢。但愿如此。
如果您想要完整版的功能背后的推理,可能值得一读PEP 498

D
Dimitris Fasarakis Hilliard

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

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

此 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 方法调用 1.2x)

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

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


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

为了以 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 ('test')
              2 STORE_FAST               0 (a)

 12           4 LOAD_FAST                0 (a)
              6 FORMAT_VALUE             0
              8 RETURN_VALUE
None
 15           0 LOAD_CONST               1 ('{a}')
              2 LOAD_ATTR                0 (format)
              4 LOAD_CONST               2 ('test')
              6 LOAD_CONST               3 (('a',))
              8 CALL_FUNCTION_KW         1
             10 RETURN_VALUE
None

可以看到 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 这个 dis 到底是做什么的?还;您如何从印刷文本中获取这些信息?
@Vicrobot dis 是反汇编的缩写。它采用编译函数的字节码,并将 python 虚拟机指令(二进制数据)解码为人类可读的单词。 python虚拟机是一个stack based vm,所以所有的“LOAD”和“STORE”命令都是指从堆栈中推送和拉取数据。有关 dis 库的更多信息,请参阅 here
w
wjandrea

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

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


c
c0dezer019

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

string = f'This is a {object}'

比阅读更容易

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

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


R
RinSlow

如果您想继续支持 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 的直接端口,不支持格式化