36

Since python 3.6, the shortest and most performant way to format values into a string are PEP 498 f-strings (e.g. f'Hello {name}').

Converting older formatting types ('Hello %s' % name, 'Hello {}'.format(name) ) to the new one in an existing code base appears to be a task that could be automated, however I could not find any tool doing this. Is there a tool to automatically convert literals using old string formatting to f-strings?

mari.mts
  • 683
  • 5
  • 9
  • 1
    You're sure you want to do that? Because then, if want to share your code with other people and they have a Python version lower than 3.6, then it won't work for them. – Nakor Jul 03 '19 at 19:53
  • @Nakor In my company Python 3.5 got deprecated, and we didn't use python 2 much (which will be deprecated in 6 months as well). But you are right, this is important to keep in mind! – mari.mts Jul 03 '19 at 20:01

2 Answers2

47

You can use flynt to convert multiple python files to use f-strings.

To run it, you need a python 3.6+ interpreter. Then, its as simple as:

pip install flynt
flynt [relative or absolute path to the root of your project]

Keep in mind that it will change files in place, so it is advisable to commit those to git or SVC system of your preference.

Here is an article describing the pros and cons of f-strings:

https://medium.com/@ikamen/f-strings-make-your-python-code-faster-and-more-readable-today-579ef9ca0313

Disclaimer: I am the author of flynt package.

ikamen
  • 3,175
  • 1
  • 25
  • 47
  • 1
    I almost started to cry when I had to edit someone elses god-awful code. They used concats mostly, so I had to use `flynt --transform-concats`. It took 0.5s and the character count reduction was "68198 (99.70%)"! – MrTomRod Apr 04 '23 at 16:34
8

It looks like pyupgrade is capable of both converting % formatting to format calls, and format calls to f-strings

printf-style string formatting

Availability:

Unless --keep-percent-format is passed.

'%s %s' % (a, b)                  # '{} {}'.format(a, b)
'%r %2f' % (a, b)                 # '{!r} {:2f}'.format(a, b)
'%(a)s %(b)s' % {'a': 1, 'b': 2}  # '{a} {b}'.format(a=1, b=2)

f-strings

Availability:

--py36-plus is passed on the commandline.

'{foo} {bar}'.format(foo=foo, bar=bar)  # f'{foo} {bar}'
'{} {}'.format(foo, bar)                # f'{foo} {bar}'
'{} {}'.format(foo.bar, baz.womp}       # f'{foo.bar} {baz.womp}'

note: pyupgrade is intentionally timid and will not create an f-string if it would make the expression longer or if the substitution parameters are anything but simple names or dotted names (as this can decrease readability).

Francisco
  • 10,918
  • 6
  • 34
  • 45