В мире программирования, особенно при разработке на Python, часто возникает необходимость не просто выводить статические строки, но и динамически встраивать в них данные, чтобы отобразить информацию пользователю в удобном и понятном виде. Это требует использования специальных методов, которые позволяют форматировать строки таким образом, чтобы они могли включать переменные, результаты вычислений и другие динамические элементы.
Эти методы как раз и называются - форматированием строк.
Форматирование строк — это процесс создания строковых представлений данных, которые могут включать в себя как статический текст, так и динамические элементы, такие как переменные, выражения и другие данные. Цель форматирования строк заключается в обеспечении удобного и понятного способа представления информации, что особенно важно при выводе данных пользователю или при записи их в файлы.
Форматирование строк не только улучшает читаемость и интерпретируемость данных, но и является ключевым аспектом при создании профессиональных и эффективных приложений. В Python, благодаря его гибкости и мощным встроенным функциям, разработчики имеют несколько вариантов для достижения этой цели.
История развития
Форматирование строк в Python прошло через несколько этапов развития, начиная с самых ранних версий языка и до современных реализаций, которые обеспечивают высокую гибкость и удобство использования. Вот краткий обзор ключевых моментов этого развития:
Оператор %
Оператор %
для форматирования строк был доступен с самого начала существования Python, то есть с первой версии языка. Python 1.0, выпущенный в январе 1994 года, уже поддерживал этот оператор. Он был вдохновлен аналогичным оператором в языке C и использовался для вставки значений в строковые шаблоны с помощью плейсхолдеров.
Плейсхолдеры - это места в строке, куда будет выполнена подстановка. Обладающие определенным синтаксисом.
Для форматирования мы можем использовать следующие плейсхолдеры:
Синтаксис | Определение |
---|---|
%s | для вставки строк |
%d | для вставки целых чисел |
%f | для вставки дробных чисел. Для этого типа также можно определить через точку количество знаков в дробной части |
%e | выводит число в экспоненциальной записи |
%g | для автоматического выбора между обычной и экспоненциальной записью. |
%% | умножает значение на 100 и добавляет знак процента |
%x | Для представления целочисленных значений в шестнадцатеричном виде |
При вызове метода % в него в качестве аргументов передаются значения, которые вставляются на место плейсхолдеров.
Форматирование строк и целых чисел:
name = "Alice"
age = 30
print("My name is %s and I am %d years old." % (name, age))
Форматирование дробных чисел с указанием точности:
pi = 3.14159
print("The value of pi is approximately %.2f." % pi)
# Вывод: The value of pi is approximately 3.14.
Форматирование с использованием запятой в качестве разделителя разрядов:
number = 1234567
print("The number is %d and with commas it looks like %d." % (number, number))
# Вывод: The number is 1234567 and with commas it looks like 1234567.
Форматирование чисел в экспоненциальной записи:
number = 123456789
print("The number in scientific notation is %e." % number)
# Вывод: The number in scientific notation is 1.234568e+08.
Форматирование процентов:
percentage = 0.75
print("The percentage is %.2f%%." % (percentage * 100))
# Вывод: The percentage is 75.00%.
Использование словарей для форматирования строк с помощью оператора %
позволяет ссылаться на переменные по именам, что делает процесс форматирования более удобным и упрощает его модификацию в будущем.
Этот подход избавляет от необходимости следить за порядком передаваемых значений, так как каждое значение связывается с соответствующим ключом в словаре. Однако, этот метод требует большего объема кода.
name = "Alice"
errno = 0xbadc0ffee
print(
'Hello %(name)s, an error with code 0x%(errno)x has occurred!' % {
"name": name, "errno": errno
}
)
# Вывод: 'Hello Alice, an error with code 0xbadc0ffee has occurred!'
Дополнительные параметры форматирования
Ширина поля: Можно указать минимальную ширину поля, в котором будет отображаться значение. Например,
%10s
выровняет строку по правому краю в поле шириной 10 символов.
name = "Alice"
print("|%10s|" % name)
# Вывод: | Alice|
Выравнивание: Можно использовать флаги
-
для выравнивания по левому краю и+
для отображения знака числа.
number = 42
print("|%-10d|" % number) # Выравнивание по левому краю
print("|%+10d|" % number) # Отображение знака
# Вывод: |123456789 |
# Вывод: |+123456789|
Заполнение нулями: Можно заполнить пустое пространство нулями, используя флаг
0
.
number = 42
print("|%010d|" % number) # Заполнение нулями
# Вывод: |0000000042|
Оператор %
для форматирования строк, хотя и был полезен и широко использовался, но имел несколько критичных недостатков:
Оператор
%
имел ограниченные возможности для форматирования, особенно в части управления выравниванием, заполнением и другими аспектами.Оператор
%
был уязвим для атак, связанных с форматированием строк, таких как инъекция вредоносного кода через непроверенные входные данные.Ну и конечно же, оператор
%
был недостаточно гибким.
Все эти недостатки привели к тому, что в 2008 году, был добавлен новый метод для форматирования, который так и назывался - format
. Интересен и тот факт, что он был доступен не только в новой версии Python 3.0, но и в обновлении для старой версии языка (Python 2.6).
Метод format
Данный метод унаследовал все возможности оператора %
и при этом расширил его функционал.
Плюсами данного метода стали:
Возможность явного использования именованных и позиционных аргументов.
Расширение функциональных возможностей форматирования, например управление выравниванием, заполнением, точностью чисел и разделителем разрядов.
Улучшение безопасности и избавление от возможных инъекций.
Возможность расширения за счёт переопределения метода
__format__
в пользовательских классахУлучшение читаемости благодаря явному указанию аргументов и возможности использования именованных параметров.
Теперь общий синтаксис плейсхолдера выглядит так: {:плейсхолдер}
. Это означает, что плейсхолдеры теперь заключаются в фигурные скобки, а оператор %
был заменен на :
.
В зависимости от плейсхолдера можно добавлять дополнительные параметры. Например, для форматирования чисел float можно использовать следующие параметры
{:[количество_символов][запятая][.число_знаков_в_дробной_части] плейсхолдер}
При вызове метода format в него в качестве аргументов передаются значения, которые вставляются на место плейсхолдеров:
name = "Python"
welcome_phrase = "Hello {:s}!"
print(welcome_phrase.format(name))
# Вывод: Hello Python!
В качестве результата метод format()
возвращает новую отформатированную строку. Это означает, что мы можем присвоить результат выполнения операции переменной:
your_welcome = welcome_phrase.format(name)
Если форматируемое число больше 999, то мы можем указать в определении плейсхолдера, что мы хотим использовать запятую в качестве разделителя разрядов:
source = "{:,d} символов"
print(source.format(5000))
# Вывод: 5,000 символов
Для дробных чисел, то есть таких, которые представляют тип float, перед кодом плейсхолдера после точки можно указать, сколько знаков в дробной части мы хотим вывести:
number = 12.3456789
print("{:.2f}".format(number)) # 12.34
print("{:.3f}".format(number)) # 12.345
print("{:.4f}".format(number)) # 12.3456
print("{:,.2f}".format(12345.12345)) # 12,345.12
Важным нововведением стало и то, что format
стал поддерживать дату и время:
from datetime import datetime
now = datetime.now()
print("Today is {:%Y-%m-%d}.".format(now))
# Вывод: Today is 2024-07-21.
Несмотря на то, что этот способ обладает всем необходимым функционалом - это не стало пределом. Так 23 декабря 2016 года была выпущена версия Python 3.6 в которой появились...
f-строки
F-строки предоставляют удобный и эффективный способ встраивания выражений Python прямо в строковые литералы, что делает их очень популярным и предпочтительным методом форматирования строк в современном Python.
F-строки обозначаются префиксом f
или F
перед строковым литералом и позволяют включать выражения Python внутри фигурных скобок {}
, которые затем вычисляются и подставляются в строку. Например:
name = "Alice"
age = 30
print(f"Hello, {name}! You are {age} years old.")
# Вывод: Hello, Alice! You are 30 years old.
А что с плэйсхолдерами?
Благодаря использование синтаксиса фигурных скобок F-строки поддерживают все стандартные спецификаторы форматирования, которые мы рассматривали в предыдущих методах.
Также с помощью специальных символов можно задать длину строки при форматировании:
<N: выравнивает строку по левому краю и дополняет ее пробелами с правой стороны до длины N
>N: выравнивает строку по правому краю и дополняет ее пробелами с левой стороны до длины N
^N: выравнивает строку по центру и дополняет ее пробелами с левой и правой стороны до длины N
.N: задает точную длину строки. Если в ней больше N символов, то она усекается
Например, если требуется добавить символы "0" слева (для выравнивания по правому краю), справа (для выравнивания по левому краю) или слева и справа (для выравнивания посередине) от исходной строки до достижения длины в 9 символов:
print(f"{123:0>9}") # Вывод: 000000123
print(f"{123:0<9}") # Вывод: 123000000
print(f"{123:0^9}") # Вывод: 000123000
А теперь мы более подробно рассмотрим возможности и нововведения данного метода форматирования, про которые вы, возможно, не знали:
Небольшие полезности
1) Начиная с Python 3.8, f-строки поддерживают специальный синтаксис для вывода имен переменных вместе с их значениями. Это называется "отладкой" (debugging). Синтаксис выглядит следующим образом:
x = 10
y = 25
print(f"{x = }, {y = }")
2) F-строки позволяют встраивать выражения Python прямо в строковые литералы. Это делает код более компактным и читаемым. Например:
a = 5
b = 10
print(f"The sum of {a} and {b} is {a + b}.")
# Вывод: The sum of 5 and 10 is 15.
3) Плюсы есть и в ООП. Так методы __repr__
и __str__
в Python используются для создания строковых представлений объектов. По умолчанию для формирования читаемого строкового представления экземпляров классов используется метод __str__
. Однако, если требуется использовать метод __repr__
вместо __str__
, можно воспользоваться флагом преобразования !r
в f-строках.
Вот пример, демонстрирующий использование этих методов:
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('{self.first_name}', '{self.last_name}')"
user = User("Pablo", "Chikoni")
print(f"{user}") # Вывод: Pablo Chikoni
print(f"{user!r}") # Вывод: User('Pablo', 'Chikoni')
Оптимизированность
Следующим плюсом является и то, что f-строки сильно оптимизированы и работают быстрее, чем другие методы форматирования строк, такие как str.format()
или оператор %
. Это делает их предпочтительным выбором для многих задач, особенно когда требуется высокая производительность.
Постараюсь вам доказать это, следующим примером:
import timeit
# Примеры строк для форматирования
name = "Alice"
age = 30
# Функция для измерения времени выполнения
def measure_time(stmt, number=1000000):
return timeit.timeit(stmt, number=number, globals=globals())
# Измерение времени выполнения для каждого метода
f_string_time = measure_time('f"My name is {name} and I am {age} years old."')
format_time = measure_time('"My name is {} and I am {} years old.".format(name, age)')
percent_time = measure_time('"My name is %s and I am %d years old." % (name, age)')
# Вывод результатов
print(f"f-string time: {f_string_time:.6f} seconds")
print(f"str.format() time: {format_time:.6f} seconds")
print(f"operator % time: {percent_time:.6f} seconds")
выведет:
f-string time: 0.166108 seconds
str.format() time: 0.330560 seconds
operator % time: 0.276897 seconds
Как вы можете заметить, скорость выполнения отличается почти в 2 раза, от всех предыдущих методов форматирования. Так что следуя Дзен Python, а именно пункту “Должен быть один и только один очевидный способ сделать что-то в Python”. Мы бы рекомендовали вам использовать f-строки.
Если вам понравилась данная статья, то вы можете подписаться на наш телеграмм канал. В нём вы найдёте ещё множество интересных и полезных статьей!