Форматирование строк в Python

от автора

В мире программирования, особенно при разработке на Python, часто возникает необходимость не просто выводить статические строки, но и динамически встраивать в них данные, чтобы отобразить информацию пользователю в удобном и понятном виде. Это требует использования специальных методов, которые позволяют форматировать строки таким образом, чтобы они могли включать переменные, результаты вычислений и другие динамические элементы.

Эти методы как раз и называются — форматированием строк.

Форматирование строк — это процесс создания строковых представлений данных, которые могут включать в себя как статический текст, так и динамические элементы, такие как переменные, выражения и другие данные. Цель форматирования строк заключается в обеспечении удобного и понятного способа представления информации, что особенно важно при выводе данных пользователю или при записи их в файлы.

Форматирование строк не только улучшает читаемость и интерпретируемость данных, но и является ключевым аспектом при создании профессиональных и эффективных приложений. В Python, благодаря его гибкости и мощным встроенным функциям, разработчики имеют несколько вариантов для достижения этой цели.

История развития

Форматирование строк в Python прошло через несколько этапов развития, начиная с самых ранних версий языка и до современных реализаций, которые обеспечивают высокую гибкость и удобство использования. Вот краткий обзор ключевых моментов этого развития:

Оператор %

Оператор % для форматирования строк был доступен с самого начала существования Python, то есть с первой версии языка. Python 1.0, выпущенный в январе 1994 года, уже поддерживал этот оператор. Он был вдохновлен аналогичным оператором в языке C и использовался для вставки значений в строковые шаблоны с помощью плейсхолдеров.

Плейсхолдеры — это места в строке, куда будет выполнена подстановка. Обладающие определенным синтаксисом.

Для форматирования мы можем использовать следующие плейсхолдеры:

Синтаксис

Определение

%s

для вставки строк

%d

для вставки целых чисел

%f

для вставки дробных чисел. Для этого типа также можно определить через точку количество знаков в дробной части

%e

выводит число в экспоненциальной записи

%g

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

%%

умножает значение на 100 и добавляет знак процента

%x

Для представления целочисленных значений в шестнадцатеричном виде

При вызове метода % в него в качестве аргументов передаются значения, которые вставляются на место плейсхолдеров.

  1. Форматирование строк и целых чисел:

name = "Alice" age = 30 print("My name is %s and I am %d years old." % (name, age))
  1. Форматирование дробных чисел с указанием точности:

pi = 3.14159 print("The value of pi is approximately %.2f." % pi) # Вывод: The value of pi is approximately 3.14.
  1. Форматирование с использованием запятой в качестве разделителя разрядов:

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. 
  1. Форматирование чисел в экспоненциальной записи:

number = 123456789 print("The number in scientific notation is %e." % number) # Вывод: The number in scientific notation is 1.234568e+08.
  1. Форматирование процентов:

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|

Оператор % для форматирования строк, хотя и был полезен и широко использовался, но имел несколько критичных недостатков:

  1. Оператор % имел ограниченные возможности для форматирования, особенно в части управления выравниванием, заполнением и другими аспектами.

  2. Оператор %  был уязвим для атак, связанных с форматированием строк, таких как инъекция вредоносного кода через непроверенные входные данные.

  3. Ну и конечно же, оператор % был недостаточно гибким.

Все эти недостатки привели к тому, что в 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-строки.

Если вам понравилась данная статья, то вы можете подписаться на наш телеграмм канал. В нём вы найдёте ещё множество интересных и полезных статьей!


ссылка на оригинал статьи https://habr.com/ru/articles/830282/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *