Форматирование строк в Python
Три метода форматирования строк в Python: оператор %, str.format() и f-строки — с примерами для чисел, выравнивания, дат и не только.
Форматирование строк позволяет динамически создавать строки, вставляя переменные, выражения и вычисленные значения в шаблон. Python предлагает три различных подхода: устаревший оператор %, универсальный метод str.format() и современный синтаксис f-строк — каждый со своими преимуществами и подходящими сценариями использования.
В этой главе рассматриваются:
- Когда и почему использовать каждый метод форматирования
- Оператор
%(устаревший, но всё ещё распространён в логах и старых кодовых базах) str.format()с позиционными и именованными плейсхолдерами- f-строки (рекомендуемый современный подход)
- Спецификаторы формата: ширина, выравнивание, точность, заполнение, знак и основание системы счисления
- Форматирование чисел, процентов, дат и времени
- Распространённые ловушки и пограничные случаи
Подробное описание f-строк — включая выражения, условную логику и улучшения Python 3.12 — см. в главе Python f-Strings.
Какой метод использовать?
| Метод | Версия Python | Когда использовать |
|---|---|---|
Оператор % | 2.x / 3.x | Устаревший код, модуль logging, очень простые подстановки |
str.format() | 2.6+ | Когда нужны многократно используемые строки формата или именованные аргументы |
| f-строки | 3.6+ | Новый код — самые быстрые, наиболее читаемые, поддерживают встроенные выражения |
Если вы не поддерживаете код на Python 2 или старой версии Python 3, используйте f-строки. Они вычисляются во время выполнения, не создают дополнительных накладных расходов на вызов и держат имя переменной рядом с тем местом, где оно появляется в строке.
Оператор % (устаревшее форматирование)
Оператор % подставляет значения в строку формата, используя спецификаторы преобразования в стиле C.
Распространённые спецификаторы преобразования:
| Спецификатор | Значение |
|---|---|
%s | Строка (вызывает str() для значения) |
%d | Знаковое целое число |
%f | Число с плавающей точкой |
%r | repr() значения |
%% | Символ % |
Ширина и точность с %
Ширину поля и точность десятичного представления можно указать прямо в спецификаторе:
pi = 3.14159265
print("%10.3f" % pi) # right-aligned in a 10-char field, 3 decimal places
# 3.142
print("%-10.3f|" % pi) # left-aligned
# 3.142 |
print("%010.3f" % pi) # zero-padded
# 000003.142Ловушка: одиночное значение против кортежа
При подстановке одного значения безопаснее передавать его в кортеже:
value = "hello"
# Risky — if value were itself a tuple, this would fail:
# print("Got: %s" % value)
# Safe:
print("Got: %s" % (value,))
# Got: hellostr.format() — гибкое форматирование с плейсхолдерами
Метод str.format() пришёл на смену оператору % в Python 2.6+. В качестве плейсхолдеров он использует {} и поддерживает позиционные, индексированные и именованные аргументы.
Позиционные и индексированные плейсхолдеры
Именованные (keyword) плейсхолдеры
Именованные плейсхолдеры делают строки формата самодокументированными и особенно удобны, когда одно и то же значение встречается несколько раз или когда строка формата берётся из файла конфигурации.
Повторное использование строк формата
Поскольку str.format() принимает строку на вход, шаблон можно сохранить в переменной и использовать повторно:
template = "Hello, {name}! You have {count} new messages."
print(template.format(name="Alice", count=3))
print(template.format(name="Bob", count=0))
# Hello, Alice! You have 3 new messages.
# Hello, Bob! You have 0 new messages.f-строки — современное форматирование в Python
f-строки (форматированные строковые литералы) добавляют перед строкой префикс f или F и вычисляют любое выражение внутри {} во время выполнения. Они доступны начиная с Python 3.6 и являются рекомендуемым подходом для нового кода.
name = "John"
age = 25
print(f"My name is {name} and I am {age} years old.")
# My name is John and I am 25 years old.f-строки поддерживают любые допустимые выражения Python внутри фигурных скобок — арифметику, вызовы методов, условные выражения и многое другое:
items = ["apple", "banana", "cherry"]
print(f"Cart has {len(items)} items. First: {items[0].upper()}.")
# Cart has 3 items. First: APPLE.
x = -7
print(f"Absolute value: {abs(x)}")
# Absolute value: 7Полное руководство, включая отладку с =, многострочные f-строки и улучшения Python 3.12, см. в главе Python f-Strings.
Спецификаторы формата: мини-язык
И str.format(), и f-строки используют один и тот же мини-язык спецификации формата внутри {} после двоеточия:
{[field_name]:[fill][align][sign][#][0][width][grouping][.precision][type]}В таблице ниже приведены наиболее полезные параметры:
| Параметр | Символ | Эффект |
|---|---|---|
| Выравнивание | < > ^ | По левому краю, по правому краю, по центру |
| Заполнение | любой символ | Заполняет отступ (используется вместе с выравниванием и шириной) |
| Знак | + - | Показывать + для положительных; только минус по умолчанию; пробел для положительных |
| Префикс | # | 0x для шестнадцатеричного, 0o для восьмеричного, 0b для двоичного |
| Дополнение нулями | 0 | Заполнение нулями вместо пробелов |
| Ширина | целое число | Минимальная ширина поля |
| Разделитель групп | , или _ | Разделитель тысяч |
| Точность | .n | Количество знаков после запятой (для чисел с плавающей точкой) или максимальное число символов (для строк) |
| Тип | d f e g x o b % | Целое, число с плавающей точкой, научная нотация, общий формат, шестнадцатеричный, восьмеричный, двоичный, проценты |
Выравнивание и ширина
text = "hello"
print(f"{text:<10}|") # left-aligned in 10-char field
# hello |
print(f"{text:>10}|") # right-aligned
# hello|
print(f"{text:^10}|") # centered
# hello |
print(f"{text:*^10}|") # centered, filled with *
# **hello***|Те же спецификаторы выравнивания работают с str.format(). Вот пример, совмещающий выравнивание и точность:
Форматирование чисел
x = 123.456789
print(f"{x:.2f}") # two decimal places
# 123.46
print(f"{x:,.2f}") # thousands separator, two decimal places
# 123.46
print(f"{x:+.2f}") # explicit plus sign for positive numbers
# +123.46
print(f"{x:10.2f}") # right-aligned in a 10-char field
# 123.46
print(f"{x:<10.2f}|") # left-aligned
# 123.46 |
print(f"{x:010.2f}") # zero-padded to 10 characters
# 0000123.46Большие числа и проценты
population = 8_100_000_000
print(f"{population:,}") # comma separator
# 8,100,000,000
print(f"{population:_}") # underscore separator (Python 3.6+)
# 8_100_000_000
ratio = 0.8567
print(f"{ratio:.1%}") # percentage, one decimal place
# 85.7%Основания систем счисления
n = 255
print(f"{n:d}") # decimal (default)
# 255
print(f"{n:x}") # lowercase hexadecimal
# ff
print(f"{n:X}") # uppercase hexadecimal
# FF
print(f"{n:#x}") # hex with 0x prefix
# 0xff
print(f"{n:o}") # octal
# 377
print(f"{n:b}") # binary
# 11111111
print(f"{n:#b}") # binary with 0b prefix
# 0b11111111Те же спецификаторы можно использовать с str.format():
Научная нотация
avogadro = 6.02214076e23
print(f"{avogadro:.3e}") # scientific notation, 3 decimal places
# 6.022e+23
print(f"{avogadro:.3E}") # uppercase E
# 6.022E+23
print(f"{avogadro:.3g}") # general: compact form, removes trailing zeros
# 6.02e+23Форматирование строк с format() и f-строками
Все три подхода дают одинаковый результат для простой подстановки:
Спецификаторы для строк позволяют управлять усечением и дополнением:
s = "Python"
print(f"{s:.3}") # truncate to 3 characters
# Pyt
print(f"{s:10}") # pad to width 10 (left-aligned by default for strings)
# Python
print(f"{s:>10}") # right-aligned
# Python
print(f"{s:*^12}") # centered, filled with *
# ***Python***Форматирование дат и времени
При форматировании объектов datetime в f-строках или str.format() используйте коды формата strftime внутри фигурных скобок:
import datetime
date = datetime.datetime(2024, 3, 15, 10, 30, 0)
# Default string representation
print(f"Default: {date}")
# Default: 2024-03-15 10:30:00
# strftime codes inside the format spec
print(f"Formatted: {date:%B %d, %Y}")
# Formatted: March 15, 2024
print(f"Time only: {date:%H:%M:%S}")
# Time only: 10:30:00
print(f"ISO-style: {date:%Y-%m-%d}")
# ISO-style: 2024-03-15Тот же синтаксис работает с str.format():
import datetime
date = datetime.datetime(2024, 3, 15, 10, 30, 0)
print("The date is {:%B %d, %Y}".format(date))
# The date is March 15, 2024Дополнительные техники форматирования дат см. в главе Python Modify Strings, посвящённой методам работы со строками.
Продвинутые техники
Вложенные выражения в f-строках
f-строки позволяют вычислять спецификатор формата динамически:
width = 10
precision = 3
value = 3.14159
print(f"{value:{width}.{precision}f}")
# output: 3.142 (right-aligned in a 10-char field, 3 decimal places)Спецификатор формата с format() и переменными
Та же техника работает с str.format() при помощи вложенных {}:
width = 8
print("{:{width}}".format("left", width=width))
# left Условное форматирование в f-строках
Поскольку f-строки вычисляют любое выражение, внутри них можно использовать условные выражения:
score = 73
label = f"{'pass' if score >= 60 else 'fail'}"
print(f"Score {score}: {label}")
# Score 73: passОтладка с = (Python 3.8+)
Добавьте = внутри f-строки, чтобы вывести и выражение, и его значение — очень удобно для отладки:
x = 42
y = x * 2
print(f"{x=}, {y=}")
# x=42, y=84Распространённые ловушки
1. Экранирование фигурных скобок. Чтобы включить в форматированную строку буквальный символ { или }, удвойте его:
print(f"Use {{curly braces}} in f-strings")
# Use {curly braces} in f-strings2. Кавычки внутри f-строк. В Python 3.11 и ранее выражение внутри {} не может использовать тот же тип кавычек, что и внешняя f-строка:
names = ["Alice", "Bob"]
# Wrong in Python <= 3.11:
# print(f"First: {names[0].upper()}") -- this is fine
# print(f"{'Alice'.upper()}") -- single quotes inside double-quoted f-string is fine
# But nesting the same quotes fails:
# print(f"{names["Alice"]}") -- SyntaxError in <= 3.11
# Safe approach for <= 3.11:
key = "Alice"
print(f"{key.upper()}")
# ALICE3. Ловушка с кортежем при %. При использовании форматирования % с одиночным значением, которое само является кортежем, оберните его:
coords = (10, 20)
# This raises TypeError because % sees a 2-element tuple:
# print("Position: %s" % coords)
# Fix: wrap in a 1-element tuple
print("Position: %s" % (coords,))
# Position: (10, 20)4. str.format() и безопасность. Никогда не передавайте ненадёжный пользовательский ввод в качестве строки формата для str.format() — вредоносный шаблон может получить доступ к атрибутам объектов и привести к утечке данных. f-строки всегда являются жёстко заданными строками в коде, поэтому они не подвержены этой уязвимости.
Практическое сравнение
Вот одинаковый вывод, созданный всеми тремя методами бок о бок:
item = "widget"
qty = 42
unit_price = 4.5
# % operator
print("%-12s %4d $%7.2f" % (item, qty, unit_price))
# str.format()
print("{:<12} {:>4} ${:>7.2f}".format(item, qty, unit_price))
# f-string
print(f"{item:<12} {qty:>4} ${unit_price:>7.2f}")
# All print:
# widget 42 $ 4.50Итоги
- Используйте f-строки для нового кода Python 3.6+: они наиболее читаемы и быстры.
- Используйте
str.format(), когда нужен многократно используемый строковый шаблон или необходима поддержка Python 2.6+. - Используйте
%только в устаревшем коде или при работе с модулемlogging(который откладывает форматирование до момента фактической записи в лог). - Мини-язык спецификации формата (
width,precision,align,fill,type) применяется одинаково как кstr.format(), так и к f-строкам.
Связанные главы:
- Python f-Strings — подробное описание выражений f-строк и возможностей Python 3.12
- Python Strings — основы строк, индексирование и срезы
- Modify Strings — встроенные строковые методы
- Escape Characters — специальные символы в строках