Python 3.6 added yet another way to do string substitution that they are calling “Formatted String Literals”. You can read all about the concept in PEP 498. I take a bit of umbrage here in that the Zen of Python states that There should be one– and preferable only one –obvious way to do it. Now Python has three ways. Let’s take a walk down memory lane before we talk about the latest way to play with strings.
Ye Olde String Substitution
When Python first started, they followed C++ in the way they did string substitution by using %s, %i and the like. Here are a couple of examples:
>>> The %s fox jumps the %s' % ('quick', 'crevice') 'The quick fox jumps the crevice' >>> foo = 'The total of your purchase is %.2f' % 10 >>> foo 'The total of your purchase is 10.00'
The second example above demonstrates how to format a number into a float with a precision set to 2 decimal places. This method of string substitution also supports keyword arguments:
>>> 'Hi, my name is %(name)s' % {'name': 'Mike'} Out[21]: 'Hi, my name is Mike'
The syntax is a little odd and I always have to look it up to get it to work correctly.
While these methods of string substitution are still supported, a new method was invented that was supposed to be clearer and more functional. Let’s see how that looks:
>>> bar = 'You need to pay {}'.format(10.00) >>> bar 'You need to pay 10.0' >>> swede = 'The Swedish chef is know for saying {0}, {1}, {2}'.format('bork', 'cork', 'spork') >>> swede 'The Swedish chef is know for saying bork, cork, spork'
I thought this was a pretty clever new addition. However there was an additional enhancement in that you could actually use keyword arguments to specify what goes where in a string substitution:
>>> swede = 'The Swedish chef is know for saying {something}, {something}, {something}' >>> swede.format(something='bork') 'The Swedish chef is know for saying bork, bork, bork' >>> test = 'This is a {word} of your {something}'.format(word='Test', something='reflexes') >>> test 'This is a Test of your reflexes'
This is pretty cool and actually quite useful. You will see some programmers that will argue over which method is to be preferred. I have seen some even claim that the original method is actually faster than the newer one if you are doing a lot of string substitutions. Regardless, this gives you a brief glimpse of the old way of doing things. Let’s see what’s new!
Using Formatted String Literals
Starting in Python 3.6, we get Formatted String Literals or f-string. The syntax for a formatted string literal is a bit different than what we’ve seen previously:
>>> name = 'Mike' >>> f'My name is {name}' 'My name is Mike'
Let’s break this down a bit. The first thing we do is define a variable that we want to insert into a string. Next we want to tell Python that we want to create a formatted string literal. To do this, we prepend our string with the letter “f”. That means the string will be formatted. The final piece is quite similar to our last example from the previous section in that we just need to insert our variable name into the string with a pair of curly braces around it. Then Python does some magic and we get a new string printed out. This is actually quite similar to some of the Python templating languages, such as mako.
The f-string also supports certain types of conversions, such as str() via ‘!s’ and repr() via ‘!r’. Here’s an updated example:
>>> f'My name is {name!r}' Out[11]: "My name is 'Mike'"
You will note that the change in the output is pretty subtle in that all that was added is some single quotes around the variable that was inserted. Let’s take a look at something a bit more complicated, namely floating point numbers!
>>> import decimal >>> gas_total = decimal.Decimal('20.345') >>> width = 10 >>> precision = 4 >>> f'Your gas total is: {gas_total:{width}.{precision}}' 'Your gas total is: 20.34'
Here we import Python’s decimal module and create an instance of that represents a gas total. Then we set up the width of the string to be 10 characters and the precision to be 4. Finally we tell the f-string to format it for us. As you can see, the inserted text has some padding on the front end to make it 10 characters wide and the precision basically set it to 4 which truncated the 5 instead of rounding up.
Wrapping Up
The new Formatted String Literal or f-string doesn’t really add anything new to formatting strings. However it is claimed to be more flexible and less error-prone than the previous methods. I highly recommend reading the documentation and PEP 498 to help you get up to speed on this new feature so you can determine if this is the way you will be doing string substitution in the future.
Related Reading
- What’s new in Python 3.6
- PEP 498 — Literal String Interpolation
- New in Python: Syntax for variable annotations
- New in Python: Underscores in Numeric Literals
There is keyword support also in “Ye Olde String Substitution”
> ‘Hi, %(name)s’ % {‘name’: ‘Mike’}
‘Hi, Mike’
Thanks for reminding me of that. I knew I was forgetting an example. I went ahead and updated the article accordingly.
spot on about little bit awkward syntax, I literally had to look that up to post my comment 🙂
Yeah…even when I was writing that example, I made a mistake (forgot the “s”), so it’s definitely not a friendly method.
This is great when you have a bunch of substitution at once. The old way of doing the same thing:
> lover = “peter”
> loved = “mary”
> “{lover} loves {loved}!”.format(**locals())