Python: Going Beyond Basic String Formatting using f-string
Faster and More Efficient String Formatting with Python’s f-Strings
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