Python3 f-Strings and string formatting syntax

Python3 f-Strings and string formatting syntax

As of Python 3.6, f-strings are a great new way to format string. Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!

f-string Magic


Simple Syntax:

The syntax is similar to the one you used with str.format() but less verbose. Look at how easily readable this is:

>>> name = "Eric"
>>> age = 74
>>> f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'

It would also be valid to use a capital letter F:

>>> F"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'

Quotation Marks

This code will work:

>>> f"{'Eric Idle'}"
'Eric Idle'

This code will also work:

>>> f'{"Eric Idle"}'
'Eric Idle'

You can also use triple quotes:

>>> f"""Eric Idle"""
'Eric Idle'

>>> f'''Eric Idle'''
'Eric Idle'

Arbitrary Expressions

Because f-strings are evaluated at runtime, you can put any and all valid Python expressions in them. This allows you to do some nifty things.

You could do something pretty straightforward, like this:

f"{2 * 37}"
'74'

But you could also call functions. Here’s an example:

def to_lowercase(input):
    return input.lower()

name = "Eric Idle"
f"{to_lowercase(name)} is funny."

#OUTPUT:
'eric idle is funny.'

Braces

In order to make a brace appear in your string, you must use double braces:

>>> f"{{74}}"
'{74}'

Note that using triple braces will result in there being only single braces in your string:

>>> f"{{{74}}}"
'{74}'

However, you can get more braces to show if you use more than triple braces:

>>> f"{{{{74}}}}"
'{{74}}'

Number formatting

There are various formatting/conversions you can perform with strings. The following are done below

  • set decimal places :.nf where n is the number of decimal places
  • hex conversion
  • binary conversion
  • octal conversion
  • scientific notation
  • pad number with leading zeros :0n where n is the total number of characters
number = 420

# decimal places
print(f"number: {number:.2f}")
number: 420.00

# hex conversion
print(f"hex: {number:#0x}")
hex: 0x1a4

# binary conversion
print(f"binary: {number:b}")
binary: 110100100
 
# octal conversion
print(f"octal: {number:o}")
octal: 644

# scientific notation
print(f"scientific: {number:e}") 
scientific: 4.200000e+02
 
# total number of characters
print(f"Number: {number:09}") 
Number: 000000420

What about large numbers and percentages? Let's say you have a large number, as large as Apple's market cap: you can use :, where , is the separator.
Or, if you want f string to print out a percentage value, you can use :.2% telling Python to set 2 decimal places and add a percentage sign to the end of the string.

apple_marketcap = 2.626 * 10e12
print(f"apple_marketcap = {apple_marketcap:,}") # comma separator
apple_marketcap = 26,260,000,000,000.0

percentage = 10.394394
print(f"percentage = {percentage:.2%}") # percentage
percentage = 1039.44%

Multiline f-strings

You can have multiline strings:

name = "Eric"
profession = "comedian"
affiliation = "Monty Python"
message = (
    f"Hi {name}. "
    f"You are a {profession}. "
    f"You were in {affiliation}."
)
message

#OUTPUT:
'Hi Eric. You are a comedian. You were in Monty Python.'

But remember that you need to place an f in front of each line of a multiline string. The following code won’t work:

message = (
    f"Hi {name}. "
    "You are a {profession}. "
    "You were in {affiliation}."
)
message

#OUTPUT:
'Hi Eric. You are a {profession}. You were in {affiliation}.'

But this is what will happen if you use """:

name = "Eric"
profession = "comedian"
affiliation = "Monty Python"

message = f"""
    Hi {name}. 
    You are a {profession}. 
    You were in {affiliation}.
"""

message

#OUTPUT:
'\n    Hi Eric.\n    You are a comedian.\n    You were in Monty Python.\n'

print(message)
#OUTPUT:

    Hi Eric.
    You are a comedian.
    You were in Monty Python.
company_name = "Tesla"
employee_count = 100000
mission = "To accelerate the world's transition to sustainable energy"

print(f"""
Company: {company_name}
# of employees: {employee_count:,}
Mission: {mission}
""")

Company: Tesla
# of employees: 100,000
Mission: To accelerate the world's transition to sustainable energy

Date formatting

Now, what if you want to format your dates? Let's create a sample date time value. Just like how you would format dates with pandas or in your application, you'd define the format you want in the f-string by doing :<date_format>

Below we format a UTC DateTime to:

  • no microseconds
  • date only
  • time only
  • time with AM/PM
  • 24-hour format
import datetime

today = datetime.datetime.utcnow()
print(f"datetime : {today}\n")
datetime : 2022-09-27 15:10:52.491862

print(f"date time: {today:%m/%d/%Y %H:%M:%S}")
date time: 09/27/2022 15:10:52

print(f"date: {today:%m/%d/%Y}")
date: 09/27/2022

print(f"time: {today:%H:%M:%S.%f}") 
time: 15:10:52.491862

print(f"time: {today:%H:%M:%S %p}") 
time: 15:10:52 PM

print(f"time: {today:%H:%M}")
time: 15:10

You could also do a lot more with the formatting options. Here's how you can get the weekday from the date and the day of the year. You could also do something fun like calculating how far we are into the year. It's 70%, time flies!

# Locale’s appropriate date and time representation
print(f"locale appropriate: {today:%c}")
locale appropriate: Tue Sep 27 15:10:52 2022
 
# weekday
print(f"weekday: {today:%A}")
weekday: Tuesday

# day of the year
print(f"day of year: {today:%j}")
day of year: 270

# how far are we into the year?
day_of_year = f"{today:%j}"
print(f"progress % year: {int(day_of_year)/365 * 100:.2f}%")
progress % year: 73.97%

You can find more formatting options at https://strftime.org/

Simplified Alignment and Spacing

Have you ever tried creating a table such as that for logging or visualization? Arranging the elements becomes a nightmare with several \t tab characters flying around.

This is much easier with Python f-strings using the colon : operator, followed by a an alignment operator and field width value.

Option Meaning
< Forces the field to be left-aligned within the available space (this is the default for most objects).
> Forces the field to be right-aligned within the available space (this is the default for numbers).
= Forces the padding to be placed after the sign (if any) but before the digits. This is used for printing fields in the form '+000000120'. This alignment option is only valid for numeric types. It becomes the default when '0' immediately precedes the field width.
^ Forces the field to be centered within the available space.
correct = 'correct'
phonetic_correct = 'phonetic_correct'
typo = 'typo'
phonetic_typo = 'phonetic_typo'
phonetic_distance = 'phonetic_distance'

print(f'No Spacing:')
print(f'{correct}|{phonetic_correct}|{typo}|{phonetic_typo}|{phonetic_distance}|\n')
# OUTPUT:
No Spacing:
correct|phonetic_correct|typo|phonetic_typo|phonetic_distance|

print(f'Right Aligned:')
print(f'{correct:_>10}|{phonetic_correct:_>20}|{typo:_>10}|{phonetic_typo:_>20}|{phonetic_distance:_>20}|\n')
# OUTPUT:
Right Aligned:
___correct|____phonetic_correct|______typo|_______phonetic_typo|___phonetic_distance|

print(f'Left Aligned:')
print(f'{correct:_<10}|{phonetic_correct:_<20}|{typo:_<10}|{phonetic_typo:_<20}|{phonetic_distance:_<20}|\n') 
# OUTPUT:
Left Aligned:
correct___|phonetic_correct____|typo______|phonetic_typo_______|phonetic_distance___|

print(f'Centre Aligned:')
print(f'{correct:_^10}|{phonetic_correct:_^20}|{typo:_^10}|{phonetic_typo:_^20}|{phonetic_distance:_^20}|') 
# OUTPUT:
Centre Aligned:
_correct__|__phonetic_correct__|___typo___|___phonetic_typo____|_phonetic_distance__|

print(f'{correct:^10}|{phonetic_correct:^20}|{typo:^10}|{phonetic_typo:^20}|{phonetic_distance:^20}|')
print(f'{"":_^10}|{"":_^20}|{"":_^10}|{"":_^20}|{"":_^20}|')
# OUTPUT:
 correct  |  phonetic_correct  |   typo   |   phonetic_typo    | phonetic_distance  |
__________|____________________|__________|____________________|____________________|

print(f'|{correct:^10}|{phonetic_correct:^20}|{typo:^10}|{phonetic_typo:^20}|{phonetic_distance:^20}|')
print(f'|{"":-^10}|{"":-^20}|{"":-^10}|{"":-^20}|{"":-^20}|')
# OUTPUT:
| correct  |  phonetic_correct  |   typo   |   phonetic_typo    | phonetic_distance  |
|----------|--------------------|----------|--------------------|--------------------|

Modifiers

>>> animals = 'eelčš'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eelčš.
>>> print(f'My hovercraft is full of {animals!a}.')
My hovercraft is full of 'eel\u010d\u0161'.
>>> print(f'My hovercraft is full of {animals!s}.')
My hovercraft is full of eelčš.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eelčš'.

For a reference on these format specifications, see the reference guide for the Format Specification Mini-Language .

SUBSCRIBE FOR NEW ARTICLES

@
comments powered by Disqus