Зачем вам f-strings: особенности, о которых вы не слышали

F-strings появились в Python 3.6 и стали очень удобным и полезным инструментов для форматированного вывода. Но они обладают некоторыми особенностями, о которых не все знают. Поэтому в этой статье остановимся на них

Форматированный вывод дат и времени

Код курса
DPREP
Ближайшая дата курса
по запросу
Продолжительность
ак.часов
Стоимость обучения
0 руб.

Для нужного представления даты в виде строки согласно шаблону обычно используется функция strftime (см. тут). Причем есть еще функция strptime, и их нужно не путать. Но знали ли, что это можно сделать обычным f-strings? Пример кода на Python:

import datetime
today = datetime.datetime.today()
print(f"{today:%Y-%m-%d}")
# 2022-04-05
print(f"{today:%Y}")
# 2022

“По-честному” то же самое можно было бы сделать вот так:

print(today.strftime("%Y-%m-%d"))

Узнать, какие шаблоны для даты и времени можно через man-страницу: man strftime.

Форматированный вывод имен

Начиная с Python 3.8, появилась возможность выводить имена переменных вместе с их значением через f-strings:

x = 10
y = 25
print(f"x = {x}, y = {y}")
# x = 10, y = 25
print(f"{x = }, {y = }")  # Лучше! (3.8+)
# x = 10, y = 25
print(f"{x=}, {y=}")
x=10, y=25

print(f"{x = :.3f}")
# x = 10.000

Эта особенность называется отладкой (debugging). Она позволяет писать немного меньше кода.

Магические методы __repr__ и __str__

Если вы передадите в функцию print экземпляр класса, то только узнаете имя класса, которому он принадлежит. Чтобы сделать форматированный вывод более информативным, используются магические методы __repr__ и __str__. Обычно __repr__ используется для отладочного вывода, а __str__ — для пользовательского. Поэтому чтобы вывести именно результат __repr__, в f-string добавляется флаг !r:

class User:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

    def __repr__(self):
        return f"User's name is: {self.first_name} {self.last_name}"

user = User("John", "Doe")
print(f"{user}")
# John Doe
print(f"{user!r}")
# User's name is: John Doe

Производительность

Многие удобные “фишки” и синтаксический сахар могут стоить дорого в плане производительности. Однако это не действует на f-string в Python. Посмотрите на скорость выполнения обычного вывода и с использованием f-string:

# python -m timeit -s 'x, y = "Hello", "World"' 'f"{x} {y}"'
from string import Template

x, y = "Hello", "World"

print(f"{x} {y}")  # 39.6 наносек за цикл - Быстро!
print(x + " " + y)  # 43.5 наносек за цикл
print(" ".join((x, y)))  # 58.1 наносек за цикл
print("%s %s" % (x, y))  # 103 наносек за цикл
print("{} {}".format(x, y))  # 141 наносек за цикл
print(Template("$x $y").substitute(x=x, y=y))  # 1.24 микросекунд за цикл - Медленно!

Все эти форматированные выводы были оценены с помощью timeit. И можно увидеть, что f-strings самые быстрые в этом списке. Уже ради скорости их можно использовать в своем коде.

Удобство использования

F-strings поддерживают специальный мини-язык для форматированного вывода, который дает возможность выводить так, как считается нужным.

text = "hello world"

# Center text:
print(f"{text:^15}")
# '  hello world  '

number = 1234567890
# Set separator
print(f"{number:,}")
# 1,234,567,890

number = 123
# Add leading zeros
print(f"{number:08}")
# 00000123

Вложенные f-strings в Python

Интересно, что f-strings можно вкладывать друг в друга:

number = 254.3463
print(f"{f'${number:.3f}':>10s}")
# '  $254.346'

Вложенные f-strings можно использовать еще для переменных в качестве модификаторов:

import decimal
width = 8
precision = 3
value = decimal.Decimal("42.12345")
print(f"output: {value:{width}.{precision}}")
# 'output:     42.1'

Форматированный вывод с условием

Вместе с вложенными f-strings можно добавлять условные конструкции:

import decimal
value = decimal.Decimal("42.12345")
print(f'Result: {value:{"4.3" if value < 100 else "8.3"}}')
# Result: 42.1
value = decimal.Decimal("142.12345")
print(f'Result: {value:{"4.2" if value < 100 else "8.3"}}')
# Result:      142

x = 10
y = 5
print(f"{f'{x = }' if x > 0 else f'{y = }'}")
# x = 10

Хотя читаемость такого кода оставляет желать лучше. Такую конструкцию можно использовать для отладки, а потом поменять на более понятный код.

Форматированный вывод лямбда-выражений

Еще в копилку менее читаемого кода является форматированный вывод лямбда-выражений:

print(f"{(lambda x: x**2)(3)}")
# 9

Скобки вокруг лямбда-выражения обязательны, иначе двоеточие будет считаться модификатором.

Код курса
DPREP
Ближайшая дата курса
по запросу
Продолжительность
ак.часов
Стоимость обучения
0 руб.

Еще больше подробностей о особенностях программирования на Python вы узнаете на наших образовательных курсах в лицензированном учебном центре обучения и повышения квалификации руководителей и ИТ-специалистов (менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data) в Москве:

Добавить комментарий