f-strings are pretty amazing. They're not just for making your print statements easier on the eyes, they can actually do quite a bit more. Let's start off with some basics first.
Given this bit of code, we'll go through the variations of print statement methods to insert variables.
The first is string concatenation which provided plenty of opportunity to fat finger a quotation mark or a plus symbol.
Then there is the format command which made it easier, but you had to remember to keep your variables in the right order at the end to replace the variables marked with{}.
Finally, there's f-strings which made it a whole lot easier on the eyes.
Each of the above three print statements will provide an identical output.
Output:
You can even do multi-line f-strings like this, but the ouput will look different:
Output:
One really neat trick is to use f-strings to help you debug. By placing an equals symbol after the variable name, it will print out the variable name and its value.
Output:
Let's take another example to show you how f-strings can help you debug.
Output:
Notice how it outputs the formula as well as the answer. One thing I wish it would do better is replace the inner variables with the values e.g.
((5 * 3) / 3)=5.0
So how useful is this really? I see it as more of a shortcut when you have a lot of variables you want to print out or the variable names are long e.g.
print(f'this_is_a_long_variable_name = {this_is_a_long_variable_name}')
can be shortened to:
print(f'{this_is_a_long_variable_name=}')
Let's look at some other great things you can do with f-strings. If you place a ':' after your variable name, you can assign various formatting modifiers to handle how you want the format the variable. In the above example, we used .2f. The 'f' means to output a float and the '.2' identifies we want two decimal places.
Output:
We can use a similar modifier on strings when we need to truncate the length. The '.15' modifier says to print only the first 15 characters of the string. This might be useful if you are printing output in columns and don't want a long string throwing off your columns.
Output:
When you're dealing with large numbers, you can use f-strings to use separators to separate thousands, millions, billions etc.
Output:
What if you want spaces as separators. Well, you can't do it directly, but using the replace() method you can make it happen.
Output:
Further, you can combine modifiers such as the separator and the number of decimal places in a float:
Output:
You can use the '%' to display percentages and designating you want two decimal places like the below code demonstrates:
Output:
Additionally, you can display scientific notation just as easily:
Output:
Pretty cool huh? But wait, there's more. How about a nice easy way to format the datetime.
Output:
Let's cover three special modifiers, !s, !r, !a which are string, repr and ascii respectively. In the below example, we want to convert the emoji variable to its ascii unicode and the unicode variable to its string.
Output:
Now let's quickly look at the !r (repr). For the last two lines I've used the traditional repr() function and the !r to show they are indeed the same.
Output:
If you've ever needed to show whether a number was positive or negative, you can use the '+' modifier for that.
Output:
Now let's look at one of my favorite things with f-strings... Padding. A lot of my output is data which I like to put into columns. f-strings makes this pretty easy. Let's break the below exmaple. The '11' is how many characters wide I want the column to be. The '>', '<', and '^' determine whether I want right justified, left justified or centered text respectively. I also added the * character as padding filler and a line of digits at the top so it's more clear what's happening. You can replace the * with pretty much any character as you'll see later.
Output:
So how can we use this to output data in columns. Glad you asked. Let's take a look at this code. In the below we've defined four variables with increasing character counts. Then we're going to print each variable out on a separate line using the linefeed '\n' and finally we're going to specify a column width of 15 characters. Granted, we're still working with a single column here, we'll get to multiple columns in a bit, but I wanted to show you how you can align text within a column. The first print, we're left justifying, second print, centering, and last print right justifying.
Output:
One problem with the above code is that we've hard coded our column width at 15, we can fix that with a slight modification and add a variable called cw which will be our column width.
So now, if we want to play with my column widths, we only need to change the cw variable once.
Time to play with multiple columns. Take a look at the below code. We've defined a list with tupples containing the line number, the item purchased, and the price. We iterate through these and use an f-string to print out the line number as a double digit padded with a zero, the item in a left justified 20 character column padded with periods, and then the cost as a 5 character column as a float with two decimal places.
Output:
You can see we have our line number preceeded with a zero, then our item, some eye appealing periods and then our price nicely right justified. One thing you may notice is on line 1 and 3, there is whitespace between the '$' and the price. This may or may not bother you, but let's explore how to keep the '$' with the price. To do this, we're going to nest f-strings. I wouldn't recommend doing this a lot because it can make reading your f-string which was designed to be readable, a little less readable.
If we change our print statement to include a nested f-string, then we can move the dollar sign next to the price:
Couple things to point out. The nested f-string fixes the space between the '$' and the price, but we've had to increase our column width to six to accomodate that the dollar sign is now part of the price (one string). You'll see what I mean if you change the six back to a five in the above print statement and count the characters.
Output:
We are nearing the end of this article, but we definitively can't end this without showing how f-strings can make base conversions a walk in the park.
The trick to keeping this easy is that all your conversions using f-strings should be based on your input being an integer. Provided you do this, then converting to binary, octal, lower case hex, uppercase hex and ascii character is child's play.
Output:
Sadly, we can't use the debug trick of putting an '=' symbol at the end like we did earlier so we'd know which conversion is which. We'd have to go old school print(f"Bin: {dec:b}")
You can also use the modifiers we learned earlier and do something like this:
Output:
Here's a cute trick to generate an ASCII table.
Note, there are a number of non-printing characters between 0 - 255 decimal which will mess up the formatting which is why I limited the range on this. You could easily create a list containing bad decimal values resulting in non-printing characters and skip over them in the first for loop.
Output:
Ok, that wraps this article. I hope you learned something new. I know I did.