Python: Going Beyond Basic String Formatting using f-string

Faster and More Efficient String Formatting with Python’s f-Strings

Pravash
5 min readMar 20, 2023
Python f-string

Hi Everyone! In this article I will discuss about the python f-string — A new feature which was introduced in Python 3.6 and this feature quickly became the talk of the programming world and revolutionized the way developers format strings.

I will discuss this topic in more informal style and also will explain this with examples, which will help you to get to know about it and use it in day to day coding.

Intro

An f-string is a string literal that is prefixed with the letter “f”. It allows developers to embed expressions inside string literals, using curly braces {}. These expressions are evaluated at runtime and the resulting values are inserted into the string.

Getting Started

Some of you may know about it but what you may not is that there’s a lot of extra stuff that can be put in between these curly braces.

For example, consider the following code snippet:

This example contains like how you can do debug and add Arbitrary expressions in f-string.

name = "John"
age = 30
num_val = 10
print(f"My name is {name} and I am {age} years old.")
print(f"{age = }")
print(f"{avg % 2 = }")

Here, I have used equals(=) for debugging and also used arbitrary expression for Python expressions and other simple curly braces to print the variables. When this code is executed, the output will be:

My name is John and I am 30 years old.
age = 30
num_val % 2 = 1

So, as you can see the in the first print statement, the values of the variables name and age are inserted into the string using the f-string syntax.
In the second one, I have placed a equal(‘=’) to print ‘age=’ and you can see it prints a num value. Though there’s no need for it in production code but for debugging purposes, this is very useful.
And in the last print statement, you can see that you can actually have arbitrary expression there. It prints out the ‘num_val % 2 = ’, and then the value is substituted after the equals(‘=’).

Some use cases Involves -

Conversion

In this example, if you are not aware, Inside the curly braces {} you can put an exclamation point ‘a’, exclamation point ‘r’ or exclamation point ‘s’.

For example, consider the following code snippet:


string = "Hi There 😁"
print(f"{string!a}")
print(f"{string!r}")
print(f"{string!s}")

So what these do is instead of printing the original value it will additionally do some extra work on top of it. In this example, ‘r’ will call the ‘repr’. When you execute the code, the output will be :

'Hi There \U0001f601'
'Hi There 😁'
Hi There 😁

In the first print() statement, the !a conversion flag is used to represent the string using ASCII characters.

In the second print() statement, the !r conversion flag is used to represent the string using its __repr__ method.

In the third print() statement, no conversion flag is used. This means that the string is represented using its __str__.

Formatting

Here’s a formatting example where every type can have their own formatting. In this example I have used a float value, datetime value and in the print statement I have used colon(:) to define that value formatting like for date I have used %Y%m%d and similarly for float I have used .2f(This will give you 2 decimal places). As shown in the following example:

val = 22.225
dt = datetime.utcnow()
print(f'{dt=:%Y-%m-%d}')
print(f'{val:.2f}')

Basically, colon(:) are used to do some formatting. When you run above code, It will print out:

dt=2023-02-25
22.23

So as you can see, for respective value type, It prints out the respective formatting string.

Lets, see what’s happening under the background. To know that lets define a class called OwnClass:

class OwnClass:
def __format__(self, format_type) -> str:
print(f'OwnClass __format__ called with {format_type=!r}')
return "OwnClass()"

print(f'{OwnClass():my formatting type %%MY_FORMAT%%}')

So here I have defined a format method which takes format_type as argument and the return type is of string. And when you run this code:

OwnClass __format__ called with format='my format %%MY_FORMAT%%'
OwnClass()

As you can see, after the colon(:), the string is passed as an argument to the OwnClass and Inside that It prints the format and returns a string. Here I have ignored the argument string and instead returns a default kind of string. So its up to you what you like what information you want to return.

NOTE:
There is another thing you can do like if you want to add commas(,) in the number, you can add :,.2f in the curly braces {}. For example:

sentence = '1 MB is equal to {:,.2f} bytes'.format(1000**2)
print(sentence)

When you run this code, this will print the following output:

1 MB is equal to 1,000,000.00 bytes

Multiline Strings

You can have multiline strings. For Example:

name = "John"
profession = "Artist"
place = "USA"
message = (
f"Hi {name}. "
f"Your profession is - {profession}. "
f"And you are from {place}. "
)
print(message)

When this code is executed, It will print the output as:

Hi John. Your profession is - Artist. And you are from USA.

Conditional Expressions

f-strings can also be used with conditional expressions to create dynamic strings based on certain conditions.
For example, you can use an f-string to display a message based on a person’s age:

pythonCopy code
age = 20 message = f"You are {'old' if age >= 18 else 'young'}" print(message) # Output: You are old

When this code is executed, it prints:

You are old

for-loop

Yes, you can also use loops inside f-string to iterate over any dictionary or list have them printed in a better way. Here’s an example to print out the items inside dictionary:

dct = {'a': 1, 'b': 2}
newline = "\n" # \escapes are not allowed inside f-strings
print(f'{newline.join(f"{key}: {value}" for key, value in dct.items())}')

When this code is executed, it prints:

a: 1 
b: 2

Lets compare Speed

f-string are faster than both f-%-formatting and str.format(). As you already saw, f-string are expressions evaluated at runtime rather than constant values.
Here’s a speed comparison:

import timeit
print(timeit.timeit("""name = "Eric"; age = 74; '%s is %s.' % (name, age)""", number=10000))

# OUTPUT: 0.002332228999999998
import timeit
print(timeit.timeit("""name = "Eric"; age = 74; '{} is {}.'.format(name, age)""", number=10000))

# OUTPUT: 0.0031069680000000016
import timeit
print(timeit.timeit("""name = "Eric"; age = 74; '{name} is {age}.'""", number=10000))

# OUTPUT: 0.00012703599999999704

As you can see, f-string comes to be on top.

With f-string their concise syntax and ability to embed expressions and perform operations, f-strings have become a go-to method for string formatting in Python.

Moreover, their speed and efficiency make them a preferred choice over other string formatting methods. Although f-string aren’t the only possible way for you to format strings, they are in a great position to become that one obvious way to get the job done.

I hope this article helps you understand how f-string are really cool way to format strings.

Connect with me on LinkedIn

--

--

Pravash

I am a passionate Data Engineer and Technology Enthusiast. Here I am using this platform to share my knowledge and experience on tech stacks.