Не смотря на один из принципов Python, гласящий: «Должен существовать один — и, желательно, только один – очевидный способ сделать что-то», в нашем любимом языке есть аж четыре способа отформатировать строку. Так сложилось исторически.
Это второй урок цикла, посвящённого форматированию строк. В него входят:
- Строковый оператор форматирования
- Метод format()
- f-Строки
- Шаблонные строки
В данном уроке мы познакомимся с методом строки format().
В Python 3.0 появился новый метод строки – format(). Его предназначением было развить синтаксис уже имевшегося на тот момент строкового оператора форматирования. И действительно, новый способ оказался более удобным и гибким. Есть и обратная сторона: работает он медленнее, что, в некоторых ситуациях, критично, поскольку, вопреки расхожему мнению, программисты чаще сталкиваются с обработкой больших строк, чем больших чисел.
- Параметры format()
- Возвращаемое значениеformat()
- Как работает format()?
- Базовое форматирование с format()
- Базовое форматирование для аргументов по умолчанию, позиционных и аргументов-ключевых слов.
- Форматирование чисел с format()
- Простое форматирование чисел.
- Форматирование ширины для целых чисел и чисел с плавающей точкой.
- Форматирование чисел со знаками.
- Форматирование чисел с выравниванием
- Форматирование чисел с выравниванием
- Выравнивание чисел по центру, левому и правому краю.
- Форматирование строк с format()
- Форматирование строк с полями и выравниванием.
- Обрезание строк.
- Форматирование элементов классов и словарей с format()
- Форматирование с атрибутами класса
- Форматирование элементов словаря с format().
- Аргументы как параметры в format()
- Динамическое форматирование.
- Дополнительные параметры форматирования с format()
- Форматирование по типу с format().
- Переопределение метода _format().
- Условные обозначения str() и repr() (!r и !s) с format().
- Appendix
Параметры format()
Методу format() можно передать любое количество аргументов двух видов:
- Позиционные аргументы— простой список параметров. В самой строке можно указать куда вставлять какой аргумент, используя его порядковый номер (индексация начинается с нуля):
print("Второй аргумент: {1}, первый аргумент: {0}".format(1, 2,))
# Вывод:
Второй аргумент: 2, первый аргумент: 1
Если не использовать индексы явно, то Python сделает это сам, вставляя аргументы по порядку их перечисления:
print("Первый аргумент: {}, второй аргумент: {}".format(1, 2,))
# Вывод:
Первый аргумент: 1, второй аргумент: 2
- Именованные параметры— список параметров в виде ключ=значение, доступ к которым можно получить с используя имя параметра в фигурных скобках {ключ}.
print("Первый аргумент: {первый}, "
"второй аргумент: {второй}".format(первый=1, второй=2,))
# Вывод:
Первый аргумент: 1, второй аргумент: 2
Есть несколько тонкостей, связанных с аргументами:
Если передать больше аргументов, чем указано в строке, лишние будут автоматически отброшены. Это касается, как именованных, так и позиционных параметров:
print("Первый аргумент: {}, второй аргумент: {}".format(1, 2, 3,))
print("Первый аргумент: {первый}, "
"второй аргумент: {второй}".format(первый=4, второй=5, третий=6))
# Вывод:
Первый аргумент: 1, второй аргумент: 2
Первый аргумент: 4, второй аргумент: 5
Если передать методу меньше аргументов, чем указано, интерпретатор вернёт исключение:
print("Первый аргумент: {}, второй аргумент: {}".format(1,))# Вывод:
Traceback (most recent call last):
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 9, in <module>
print("Первый аргумент: {}, второй аргумент: {}".format(1,))
IndexError: Replacement index 1 out of range for positional args tuple
Process finished with exit code 1
print("Первый аргумент: {первый}, "
"второй аргумент: {второй}".format(первый=4))
# Вывод:
Traceback (most recent call last):
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 10, in <module>
print("Первый аргумент: {первый}, "
KeyError: 'второй'
Process finished with exit code 1
Используя индексы, Вы можете пропускать позиционные аргументы:
print("Первый аргумент: {0}, третий аргумент: {2}".format(1, 2, 3,))
# Вывод:
Первый аргумент: 1, третий аргумент: 3
Один аргумент можно использовать в нескольких местах:
print("Первый аргумент: {0}, первый аргумент ещё раз: {0}".format(1, 2, 3,))
# Вывод:
Первый аргумент: 1, первый аргумент ещё раз: 1
Возвращаемое значение format()
Метод format() возвращает отформатированную строку.
Как работает format()?
Метод format() подставляет в строку переданные аргументы, применяя к ним указанные модификаторы формата.
Давайте рассмотрим пример:
print("Первый аргумент: {0:+06d}, "
"второй аргумент: {второй:>10b}".format(-1, 3, второй=2,))
# Вывод:
Первый аргумент: -00001, второй аргумент: 10
Что здесь происходит:
- Сперва в строку подставляются позиционные аргументы (-1 и 3). Поскольку в строке явно указан индекс позиционного аргумента, который надо использовать ({0}), остальные игнорируются.
- Затем подставляются именованные аргументы. В нашем случае это второй=
- Далее к выбранным аргументам применяются модификаторы формата, указанные в фигурных скобках после двоеточия. Для первого это {+06d}, что означает «вставь число, отобрази его знак и, если его ширина меньше шести символов, дополни до шести нулями». Для второго указаны следующие модификаторы: {>10b}. Они говорят интерпретатору: «выведи число в двоичной системе исчисления, дополни до десяти символов пробелами и выровняй по правому краю».
Обратите внимание, как много всего сделано всего в одной строке. Как и в случае с регулярными выражениями, такая мощь достигается благодаря лаконичному синтаксису. Но это несёт в себе и минусы:
- Модификаторы плохо воспринимаются человеком
- Достаточно ошибиться всего в одном символе, чтоб всё пошло прахом.
Реальный кейс из моей практики: описывая необходимые изменения в XSD-схеме, упустил один пробел в шаблоне значения тега XML. Итог – полная остановка всего проекта. Будьте осторожны!
Базовое форматирование с format()
Метод format() позволяет использовать простые заполнители для форматирования.
Базовое форматирование для аргументов по умолчанию, позиционных и аргументов-ключевых слов.
# аргументы по умолчанию
print("Здравствуйте, {}. Глубина Вашего внутреннего мира {} км.".format("Изольда", 0.3))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0.3 км.
# позиционные аргументы
print("Здравствуйте, {0}. Глубина Вашего внутреннего мира {1} км.".format("Изольда", 0.3))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0.3 км.
# аргументы ключевые слова
print("Здравствуйте, {имя}. "
"Глубина Вашего внутреннего мира {км} км."
.format(имя="Изольда", км=0.3))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0.3 км.
# смешанные аргументы
print("Здравствуйте, {}. "
"Глубина Вашего внутреннего мира {км} км."
.format("Изольда", км=0.3))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0.3 км.
При использовании смешанных аргументов аргументы-ключевые слова должны идти после позиционных аргументов.
Форматирование чисел с format()
С помощью спецификаторов формата можно форматировать и числа:
Типы форматирования чисел
Тип | Значение |
d | Десятичное число |
c | Символ Unicode по номеру |
b | Двоичный формат |
o | Восьмеричный формат |
x | Шестнадцатеричный формат (в нижнем регистре) |
X | Шестнадцатеричный формат (в верхнем регистре) |
n | То же, что и d, но использует местную настройку для разделения числа |
e | Экспоненциальная запись (e в нижнем регистре) |
E | Экспоненциальная запись (E в верхнем регистре) |
f | Отображать фиксированное количество знаков (по умолчанию 6) |
F | То же, что и f, только отображает inf как INF, а nan как NAN |
g | Общий формат. Округляет число до p значащих цифр (Точность по умолчанию: 6) |
G | Аналогично g, но переключается к E, если число очень большое |
% | Проценты. Делит на 100 и добавляет % в конце |
Простое форматирование чисел.
# целочисленные аргументы
print("Здравствуйте, {}. "
"Глубина Вашего внутреннего мира {км:d} км."
.format("Изольда", км=0))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0 км.
# аргументы с плавающей точкой
print("Здравствуйте, {}. "
"Глубина Вашего внутреннего мира {км:f} км."
.format("Изольда", км=0.3))
# Вывод:
Здравствуйте, Изольда. Глубина Вашего внутреннего мира 0.300000 км.
# восьмеричный, двоичный и шестнадцатеричный формат
print("Здравствуйте, {}.\n"
"Глубина Вашего внутреннего мира\n"
"в двоичной/восьмиричной/шестнадцатеричной"
" системах:\n{км:b}/{км:o}/{км:x} км."
.format("Изольда", км=999))
# Вывод:
Здравствуйте, Изольда.
Глубина Вашего внутреннего мира
в двоичной/восьмиричной/шестнадцатеричной системах:
1111100111/1747/3e7 км.
Если передать аргумент не подходящего типа, Вы получите исключение:
print("Здравствуйте, {}. "
"Глубина Вашего внутреннего мира {км:d} км."
.format("Изольда", км=0.3))
# Вывод:
Traceback (most recent call last):
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 1, in <module>
print("Здравствуйте, {}. "
ValueError: Unknown format code 'd' for object of type 'float'
Process finished with exit code 1
Форматирование ширины для целых чисел и чисел с плавающей точкой.
# целые числа с минимальной шириной
print("{:20d}".format(3))
# Вывод:
3
# ширина не работает для чисел длиннее заполнения
print("{:2d}".format(333))
# Вывод:
333
# заполнение для чисел с плавающей точкой
print("{:7.4f}".format(3.14))
# Вывод:
3.1400
# целые числа с минимальной шириной, заполненные нулями
print("{:03d}".format(7))
# Вывод:
007
# заполнение для чисел с плавающей запятой, заполненных нулями
print("{:08.3f}".format(12.2346))
Форматирование чисел со знаками.
# показать знак
print(«{:+03d}, {:+03d}».format(7, -7))
# Вывод:
+07, -07
# показать знак —
print(«{:-03d}, {:-03d}».format(7, -7))
# Вывод:
007, -07
# показать место для знака +
print(«{: 03d}, {: 03d}».format(7, -7))
# Вывод:
07, -07
Форматирование чисел с выравниванием
Операторы <, ^, > и = используются для выравнивания в том случае, если указана конкретная ширина.
Форматирование чисел с выравниванием
Тип | Значение |
< | Выравнивается по левому краю |
^ | Выравнивается по центру |
> | Выравнивается по правому краю |
= | Сдвигает знаки (+ или -) влево |
Выравнивание чисел по центру, левому и правому краю.
# целые числа с выравниванием по правому краю
print("{:7d}".format(7))
# Вывод:
7
# числа с плавающей точкой с выравниванием по центру
print("{:^7.1f}".format(3.14))
# Вывод:
3.1
# выравнивание целого числа по центру заполнено нулями
print("{:^07d}".format(3))
# Вывод:
0003000
# числа с плавающей точкой с выравниванием по правому краю и сдвигом знака
print("{:=07.1f}".format(-3.14))
# Вывод:
-0003.1
Выравнивание по левому краю с нулями для целых чисел может быть опасно, поскольку так мы добавляем числу разряды.
Форматирование строк с format()
Как и числа, строки можно форматировать с помощью format().
Форматирование строк с полями и выравниванием.
# отступ строки с выравниванием по левому краю
print("{:10}-Питончик".format("Python"))
# Вывод:
Python -Питончик
# отступ строки с выравниванием по правому краю
print("{:>10}-Питончик".format("Python"))
# Вывод:
Python-Питончик
# заполнение строк с выравниванием по центру
print("{:^10}-Питончик".format("Python"))
# Вывод:
Python -Питончик
# заполнение строк с выравниванием по центру
# и '_' - символ заполнения
print("{:_^10}-Питончик".format("Python"))
# Вывод:
__Python__-Питончик
Обрезание строк.
# обрезание строк до двух символов
print("{:.2}-Питончик".format("Python"))
# Вывод:
Py-Питончик
# обрезание строк до двух символов и заполнение
print("{:10.2}-Питончик".format("Python"))
# Вывод:
Py -Питончик
# обрезание строк до двух символов,
# заполнение символом «_» и выравнивание по центру
print("{:_^6.2}-Питончик".format("Python"))
# Вывод:
__Py__-Питончик
Форматирование элементов классов и словарей с format()
Python использует функцию getattr() для элементов класса в форме “.age”. А __getitem__() — для элементов словаря в форме “[index]”.
Форматирование с атрибутами класса
# определяем класс
class MyClass:
my_int_var = 3
my_float_var = 3.14
my_str_var = 'Python'
# обращаемся к атрибутам объекта
print("{inst.my_str_var}-Питончик".format(inst=MyClass()))
# Вывод:
Python-Питончик
Форматирование элементов словаря с format().
# объявляем словарь
my_dict = {'my_int_var': 2, 'my_str_var': 'Python'}
# выводим значения по ключу
print("{словарь[my_str_var]}-Питончик".format(словарь=my_dict))
# Вывод:
Python-Питончик
По аналогии с классом словарь передается в качестве аргумента.
Есть и более простой способ форматировать словари в Пайтоне — с помощью распаковки str.fromat(**mapping):
print("{my_str_var}-Питончик".format(**my_dict))
# Вывод:
Python-Питончик
Аргументы как параметры в format()
Параметры, такие как точность, выравнивание или символы заполнения можно передавать в качестве позиционных аргументов-ключевых слов.
Динамическое форматирование.
# динамический шаблон формата строки
string = "{:{заполнитель}{выравнивание}{ширина}}"
# передача кодов формата в качестве аргументов
print(string.format('Питон', заполнитель='_', выравнивание='^', ширина=9))
# Вывод:
__Питон__
# тот же фокус с позиционной подстановкой
string = '{:{}{}{}}'
print(string.format('Питон', '_', '^', 9))
# Вывод:
__Питон__
Дополнительные параметры форматирования с format()
format() также поддерживает форматирования по типам, например, для datetime или форматирование сложных чисел. Он внутренне вызывает __format__() для datetime и получает доступ к атрибутам сложных чисел.
Форматирование по типу с format().
import datetime
# datetime форматирование
current_datetime = datetime.datetime.now()
print("Сейчас: {:%d.%m.%Y %H:%M}".format(current_datetime))
# Вывод:
Сейчас: 22.12.2021 15:22
# форматирование комплексных чисел
my_complex = 3+14j
print("Реальная часть: {0.real} мнимая часть: {0.imag}".format(my_complex))
# Вывод:
Реальная часть: 3.0 мнимая часть: 14.0
Переопределение метода _format().
Можно запросто переопределить метод __format__() для любого объекта для создания собственного форматирования.
# пользовательский метод __format__()
class MyClass:
def __init__(self):
self.my_str_var = 'Пайтон'
def __format__(self, format):
if (format == 'Python'):
return self.my_str_var
else:
return self.my_str_var
print("Лучший язык программирования: {:Python}".format(MyClass()))
# Вывод:
Лучший язык программирования: Пайтон
Условные обозначения str() и repr() (!r и !s) с format().
Как и __format__() можно запросто переопределять метода __str__() и __repr__() объекта.
# __str__() и __repr__() сокращенно !r и !s
# реализация для класса __str__() и __repr__()
class MyClass:
def __init__(self):
self.my_str_var = 'Пайтон', 'Python'
def __str__(self):
return self.my_str_var[0]
def __repr__(self):
return self.my_str_var[1]
print("Лучший язык программирования: {!r}".format(MyClass()))
print("Лучший язык программирования: {!s}".format(MyClass()))
# Вывод:
Лучший язык программирования: Python
Лучший язык программирования: Пайтон
Appendix
Стоит упомянуть, что существует функция format(), которая очень близка по своему поведению к методу строки .format(). Пара небольших примеров из официальной документации:
print(format(1, 'f'))
print(format(1000, '#>+10,.2f'))
print(format(1000.5368, '~>+15,.2f'))
print(format('format', '.2'))
# Вывод:
1.000000
#+1,000.00
~~~~~~+1,000.54
fo
И, в завершение темы, небольшая «пасхалка» (неочевидное поведение):
string = '{}'
print(string.format('{}').format(1, 2, 3))
string = '{{}}'
print(string.format(1, 2, 3))
string = '{{{}}}'
print(string.format(1, 2, 3))
string = '{{{{}}}}'
print(string.format(1, 2, 3))
# Вывод:
1
{}
{1}
{{}}
print('{:{}{}}'.format(1, 2, 3))
# Вывод:
1
print('{{}{}}'.format(1, 2, 3))
# Вывод:
Traceback (most recent call last):
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 1, in <module>
print('{{}{}}'.format(1, 2, 3))
ValueError: Single '}' encountered in format string
Process finished with exit code 1