Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 4 из 20 Начальный 20 мин 130 XP

Формат-спецификации f-строк: цена, ширина, выравнивание

F-строка умеет не только вставлять значение, но и оформлять его: два знака после точки у цены, ровные колонки, знак числа, нули вместо пробелов. Всё это — спецификация после двоеточия.

Редакция Питоники

В уроке 3 f-строка научилась вставлять значение в текст: f'Цена: {price} руб.'. Но значение вставилось «как есть», а в реальных задачах этого мало: цена 79.5 выглядит как 79.5, а касса ждёт 79.50, колонки таблицы едут, у чисел не видно знака. Оформлением управляет формат-спецификация — короткая запись после двоеточия внутри фигурных скобок.

Двоеточие включает оформление

Двоеточие внутри f-строки включает режим оформления: всё после него — инструкция о том, как показать значение. Самая ходовая спецификация — .2f: буква f означает «показать как десятичную дробь», а цифра перед ней — сколько знаков оставить после точки:

цена с двумя знаками
price = 79.5
print(f'Цена: {price:.2f} руб.')
print(f'{1/3:.4f}')
Вывод
Цена: 79.50 руб.
0.3333

Спецификация не меняет само значение — только его вид в тексте: в переменной price по-прежнему лежит 79.5. Цифра задаёт точность с округлением: {1/3:.4f} превратил бесконечную треть в аккуратные 0.3333. А {2.675:.2f} даст 2.67, а не 2.68: число 2.675 в памяти компьютера не точное, и округление идёт по его реальному двоичному значению.

Ширина поля и выравнивание

Число после двоеточия задаёт ширину поля: Python отведёт под значение ровно столько символов, а лишнее заполнит пробелами. Символ выравнивания решает, к какому краю прижать значение: < — влево, > — вправо, ^ — по центру:

три выравнивания в поле шириной 8
word = 'кот'
print(f'{word:<8}|')
print(f'{word:>8}|')
print(f'{word:^8}|')
Вывод
кот     |
     кот|
  кот   |

Палка | в конце показывает, где поле закончилось: слово «кот» занимает три символа, остальные пять в поле шириной 8 — пробелы. Без символа выравнивания текст прижимается влево, числа — вправо: так каждому типу удобно по умолчанию.

ровные колонки прайса
items = [('Хлеб', 45.0), ('Молоко', 89.9), ('Сыр', 620.0)]
for name, cost in items:
    print(f'{name:<8}{cost:>10.2f}')
Вывод
Хлеб         45.00
Молоко       89.90
Сыр         620.00

Классика отчётов: название прижато влево, цена — вправо, и столбцы денег выстроены по разрядам, как в чеке. Спецификации складываются: {cost:>10.2f} — поле шириной 10, два знака после точки.

Знак числа и ведущие нули

Спецификация + показывает знак всегда — и у положительных чисел тоже. А ведущие нули удобны для номеров и кодов: 06 в спецификации означает «поле шириной 6, пустоту залить нулями»:

знак и нули вместо пробелов
print(f'{42:+}')
print(f'{-42:+}')
print(f'{7.5:06.2f}')
print(f'{42:05d}')
Вывод
+42
-42
007.50
00042

Сценарий: прайс на три позиции

Менеджеру нужно показать список заказов так, чтобы суммы читались столбиком, а номера заказов не разъезжались. Это ровно та задача, ради которой и придуманы спецификации: каждому столбцу задают свою ширину и своё прижатие, а цифры дробной части приводят к общему виду.

заказы в выровненных колонках
orders = [('ORD-1', 'чай', 2, 240.0), ('ORD-2', 'кофе', 1, 180.5)]
for oid, name, qty, price in orders:
    print(f'{oid:<7}{name:<8}{qty:>3}{price:>10.2f}')
Вывод
ORD-1  чай       2    240.00
ORD-2  кофе      1    180.50

Четыре спецификации в одной строке: номер прижат влево в поле 7, название — влево в поле 8, количество — вправо в поле 3, цена — вправо в поле 10 с двумя знаками. Читать такую строку неудобно, зато результат выглядит как настоящий чек.

Полная грамматика спецификации

Спецификация — не набор случайных символов, а строгий порядок частей. Python разбирает её слева направо, и если часть пропущена, всё, что после неё, сдвигается. Полный набор выглядит так:

ЧастьПримерЧто делает
Заполнитель и прижатие>10, <8, ^6ширина поля и сторона прижатия
Знак+, плюс всегда или пробел вместо плюса
Ведущий ноль06пустоту поля заливает нулями
Ширина12минимум столько символов на значение
Разделитель разрядов, или _1 234 567 вместо 1234567
Точность.2fзнаков после точки
Типd, f, x, b, sв какой системе и виде показать

Запомнить весь порядок не обязательно — на практике хватает трёх-четырёх частей. Но когда спецификация не срабатывает, причина почти всегда в нарушенном порядке: например, .2f нельзя поставить перед шириной, а знак + — после выравнивания.

Числа в других системах счисления

Спецификация # просит показать основание: для шестнадцатеричной системы добавляется префикс 0x, для двоичной — 0b, для восьмеричной — 0o. Это удобно для отладочных сообщений и вывода идентификаторов.

основания счисления
print(f'{255:#x}')
print(f'{255:#b}')
print(f'{8:#o}')
Вывод
0xff
0b11111111
0o10

Разделитель разрядов

Спецификация , ставит запятые между разрядами, а _ — подчёркивания. Для денег и больших счётчиков это читается куда лучше, чем «2450000» с нулём в середине.

разряды через запятую и подчёркивание
print(f'{1234567:,}')
print(f'{1234567:_.2f}')
Вывод
1,234,567
1_234_567.00

Ширина из переменной

Внутри спецификации можно поставить ещё одни фигурные скобки — тогда ширина подставится из переменной. Это спасает, когда формат колонки задаётся в одном месте, а используется в десяти.

динамическая ширина поля
width = 12
print(f'|{"цена":<{width}}|')
print(f'|{"1234.50":>{width}}|')
Вывод
|цена        |
|     1234.50|

Кстати, всё то же самое умеет и встроенная функция format: format(1234.5678, '.2f') вернёт '1234.57'. Это тот же механизм, только спецификация передаётся отдельным аргументом, а не внутри скобок. Проверить можно так:

format как отдельная функция
print(format(1234.5678, '.2f'))
print(format(42, '08d'))
Вывод
1234.57
00000042

Частые огрехи при оформлении

  • :>10 вместо :>10.2f — сумма покажется как 240.0, и колонка разъедется по разрядам.
  • Ширина поля меньше самой величины — обрезки не будет, значение вылезет за границу.
  • .2f на строке — ValueError: Unknown format code 'f' for object of type 'str'.
  • Округление .2f идёт по двоичному значению числа: 2.675 станет 2.67. Для денег это повод перейти на модуль decimal.

Под капотом спецификация — не магия интерпретатора, а вызов метода __format__, который есть у любого объекта в Python. Для чисел он написан на C и понимает всю грамматику, для строк — свой, а для своих классов вы можете определить его сами: тогда объект научится подставляться в f-строку по вашим правилам. Практический вывод простой: если f-строка ругается «Unknown format code», у значения просто нет нужного формат-кода.

Карточка спецификаций

СпецификацияПримерРезультатЧто делает
.2ff'{x:.2f}'79.50дробь с двумя знаками после точки
.4ff'{x:.4f}'0.3333дробь с четырьмя знаками
8f'{word:8}'кот поле шириной 8, текст влево
>10f'{x:>10}' котполе шириной 10, значение вправо
^8f'{x:^8}' кот значение по центру поля
+f'{x:+}'+42знак показывается всегда
06.2ff'{x:06.2f}'007.50ширина 6, пустота залита нулями

Читается спецификация слева направо: выравнивание, ширина, точность, тип. Весь набор нужен не каждый день — держите под рукой эту карточку, а глубже в грамматику форматов шагает урок 12 про format(). Пока же закрепите главное: двоеточие — и цена превратилась в 79.50. Следующий урок покажет, что у строк есть и заготовки похитрее — методы регистра: lower, upper и title.

Мини-практика: три ценника

Соберите три строки ценника для прайса: название прижато влево в поле 10, цена — вправо в поле 8 с двумя знаками после точки, а скидка в процентах — влево в поле 6 со знаком плюс. Важно: спецификация + работает и для целых чисел.

ценник с тремя колонками
goods = [('Хлеб', 45.0, 10), ('Молоко', 89.9, 0)]

for name, price, sale in goods:
    print(f'{name:<10}{price:>8.2f}{sale:+5d}%')
Вывод
Хлеб         45.00  +10%
Молоко       89.90   +0%

Третья колонка — целое число со знаком: у хлеба скидка 10, у молока 0, но знак плюс печатается в обоих случаях, потому что спецификация + показывает знак всегда. Правда, +0% выглядит странно — в реальном прайсе для нулевой скидки условие писали бы отдельно.

Двоеточие внутри f-строки включает режим оформления: всё после него — инструкция о том, как показать значение.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

price = 45
print(f'Итого: {price:.2f} руб.')
word = 'код'
print(f'{word:>6}|')
print(f'{word:<6}|')
print(f'{2.675:.2f}')
Проверь себя
0 / 8

1. Что выведет print(f'{79.5:.2f}')?

2. Что означает символ > в спецификации f'{name:>10}'?

3. Как прижать название товара к левому краю поля шириной 8?

4. Что выведет print(f'{7.5:06.2f}')?

5. Что произойдёт при выполнении f'{name:.2f}', если name = 'кот'?

6. Что делает спецификация + в f'{n:+}'?

7. Что выведет print(f'{1234567:>4.2f}')?

8. Что даёт спецификация # в f'{255:#x}'?

Карточки терминов
Запомнено: 0 / 10
Практика

Даны name = 'Кружка' и price = 129.5. Выведи строку чека: название прижато влево в поле шириной 10, цена — вправо в поле шириной 8 с двумя знаками после точки. Затем выведи стоимость трёх кружек так же отформатированной в поле шириной 18.

practice.py
Вопросы и ответы по уроку

Как вывести число с двумя знаками после запятой в Python?

В f-строке со спецификацией .2f: f'{price:.2f}' превратит 79.5 в '79.50'. Спецификация округляет значение по правилам двоичной арифметики и не меняет само число в переменной — только его текстовое представление.

Урок 3: f-строки

Как выровнять текст по колонкам в Python?

Задать ширину поля и символ выравнивания в f-строке: f'{name:<10}' — влево, f'{name:>10}' — вправо, f'{name:^10}' — по центру. Для чеков и таблиц названия прижимают влево, а числа вправо — разряды выстраиваются в столбик.

Почему f'{2.675:.2f}' даёт 2.67, а не 2.68?

Дробные числа хранятся в двоичном виде, и 2.675 в нём не точное — это чуть меньшее число, которое и округляется до 2.67. Так ведёт себя стандартное округление float в любом языке; для денежных расчётов используют модуль decimal.

Чем спецификации f-строк отличаются от метода format()?

Ничем в грамматике: после двоеточия пишется одна и та же спецификация, а format() — это более старый способ вызвать то же самое форматирование. F-строки короче и читаемее, поэтому стали стандартом с версии Python 3.6; полный разбор format() ждёт в уроке 12.

Урок 12: format() и старый процент

Как вывести большое число с разделителями разрядов?

Спецификацией-запятой: f'{1234567:,}' напечатает 1,234,567. Если разделителем нужен подчёркивание, как в коде, — пишут f'{1234567:_}'. Работает и с дробными: f'{1234567:_.2f}' даст 1_234_567.00.

Можно ли задать ширину поля переменной?

Да: внутрь спецификации можно вложить ещё одни фигурные скобки — f'{"цена":<{width}}' подставит ширину из переменной width. Так формат колонки задают один раз, а используют в десяти шаблонах.

Понравился урок? Сошлитесь на него

«Двоеточие внутри f-строки включает режим оформления: всё после него — инструкция о том, как показать значение.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.