f-strings in Python 3.6

我们两清 提交于 2019-11-27 01:17:39

I'm afraid that it will be deprecated during the next Python versions

Don't be, str.format does not appear (nor has a reason) to be leaving any time soon, the PEP that introduced fprefixed-strings even states in its Abstract:

This PEP does not propose to remove or deprecate any of the existing string formatting mechanisms.

Formatted strings were introduced to address some of the shortcomings other methods for formatting strings had; not to throw the old methods away and force god-knows how many projects to use f-string's if they want their code to work for Python 3.6+.


As for the performance of these, it seems my initial suspicion that they might be slower is wrong, f-strings seem to easily outperform their .format counterparts:

➜ 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

These were done against the master branch of the CPython repository as of this writing; they are definitely subject to change:

  • f-strings, as a new feature, might have possible optimizations
  • Optimizations to CPython might make .format faster (e.g Speedup method calls 1.2x)

But really, don't worry about speed so much, worry about what is more readable to you and to others.

In many cases, that's going to be f-strings, but there's some cases where format is better.

To build on Jim's answer and address your performance concern, I used python's dis module to compare the bytecode instructions for two syntactically different, but functionally equivalent functions.

import dis

def f1():
    a = "test"
    return f"{a}"

def f2():
    return "{a}".format(a='test')

print(dis.dis(f1))
print(dis.dis(f2))

The result of which is:

 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

One can see that the f-string handles the formatting without attribute or function calls, which can impose type checking and memory overhead. According to timeit this results in a roughly 3x performance gain (for my specific functions)

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

One thing not mentioned (which makes deprecation of the old techniques impossible) is that interpolation is for string literals only. Meaning, the string is rendered once at runtime. The template can not be used again with updated variables, for example:

str_template.format(args)

Another case is i18n, where string.Template is used. Many use cases would be impossible without the older techniques. Enjoy string interpolation, but don't use it where it is not appropriate, i.e. places where you need a reusable template.

If you want to keep supporting python 3.5 you could use 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!