Часто при написании кода на Python нам требуется представить объект определенным образом или включить значения каких-либо выражений внутрь строки. Для этого мы можем использовать форматирование строк. При этом в Python существуют сразу три способа форматирования строк:
оператор
%
строковый метод
format()
f-строки
Причиной такого разнообразия является развитие языка Python и постоянное совершенствование его инструментария. Один способ форматирования устаревает, ему на смену приходит новый, более удобный и практичный. Однако устаревшие способы форматирования строк было решено оставить в Python, в первую очередь для обеспечения обратной совместимости со старыми версиями языка. Каждый из способов форматирования может использоваться и по сей день.
В этой статье мы рассмотрим эволюцию способов форматирования строк и разберем их преимущества и недостатки.
Оператор %
Оператор %
является первым способом форматирования строк, который появился в Python. Он был заимствован из языка C, на котором написан основной интерпретатор Python, поэтому данный способ форматирования строк также называют форматированием в стиле С.
Для форматирования с помощью оператора %
необходимо слева от оператора указать строку с заполнителем %s
, а справа — подставляемое в нее значение.
Приведенный ниже код:
print('My name is %s' % 'James')
выводит:
My name is James
Символ s
в заполнителе обозначает преобразование подставляемого значения в формат строки. Мы можем использовать и другие форматы, наиболее важные из которых приведены в таблице ниже:
формат |
значение |
|
целое число |
|
число с плавающей точкой |
|
число в восьмеричной системе счисления |
|
число в шестнадцатеричной системе счисления |
|
число в экспоненциальном формате |
|
формальное строковое представление объекта (аналогично функции |
Например, вместо символа s
можно указать в заполнителе символ f
, который указывает на преобразование подставляемого значения в формат числа с плавающей точкой.
Если необходимо подставить в строку несколько значений, то их нужно перечислить в кортеже. При этом количество заполнителей должно соответствовать количеству подставляемых значений. В противном случае будет возбуждено исключение TypeError
. В процессе форматирования кортеж распаковывается и его элементы помещаются на место заполнителей поочередно слева направо.
Приведенный ниже код:
name = 'James'
surname = 'Bond'
result = 'My name is %s, %s %s' % (surname, name, surname)
print(result)
выводит:
My name is Bond, James Bond
Также допускается подстановка значений из словаря. Для этого в каждом заполнителе между символом %
и форматом представления необходимо в круглых скобках указать ключ словаря, значение которого требуется поместить в строку вместо заполнителя. При этом можно использовать один и тот же ключ в нескольких заполнителях.
Приведенный ниже код:
person = {'name': 'James', 'surname': 'Bond'}
result = 'My name is %(surname)s, %(name)s %(surname)s' % person
print(result)
выводит:
My name is Bond, James Bond
Основным недостатком %
-форматирования является сложность в использовании и избыточность кода в случаях, когда требуется подставить в строку большое количество значений. Кроме того, %
-форматирование имеет ряд особенностей, которые часто приводят к ошибкам. Например, стоит соблюдать осторожность при подстановке кортежа в строку, которая содержит один заполнитель.
Приведенный ниже код:
person = ('James', 'Bond')
result = 'person: %s' % person
print(result)
приводит к возбуждению исключения:
TypeError: not all arguments converted during string formatting
Вместо ожидаемого вывода person: ('James', 'Bond')
мы получаем ошибку. Это происходит потому, что за кулисами Python распаковывает кортеж и пытается поместить в строку все его элементы, однако заполнитель в строке всего один. Для решения данной проблемы можно явно преобразовать кортеж в строку.
Приведенный ниже код:
person = ('James', 'Bond')
result = 'person: %s' % str(person)
print(result)
выводит:
person: ('James', 'Bond')
Кстати, форматирование строки, в результате которого заполнители заменяются значениями, называется интерполяцией. ✍️
Начиная с Python 3.0 форматирование с помощью оператора %
считается устаревшим способом форматирования строк. Ему на смену пришел более удобный и гибкий способ — строковый метод format()
.
Строковый метод format()
Строковый метод format()
возвращает копию строки, в которой каждый заполнитель {}
заменяется строковым представлением соответствующего переданного аргумента.
Аргументы метода:
*args
— позиционные аргументы**kwargs
— именованные аргументы
При подстановке позиционных аргументов их значения помещаются на место заполнителей поочередно слева направо.
Приведенный ниже код:
name = 'James'
surname = 'Bond'
result = 'My name is {}, {} {}'.format(surname, name, surname)
print(result)
выводит:
My name is Bond, James Bond
Если количество заполнителей больше, чем количество переданных позиционных аргументов, будет возбуждено исключение IndexError
, если меньше — значения аргументов, которым не хватило заполнителей, будут отброшены.
Приведенный ниже код:
name = 'James'
surname = 'Bond'
result = 'My name is {}'.format(name, surname)
print(result)
выводит:
My name is James
Для наглядности и гибкости форматирования можно использовать порядковый номер аргумента в заполнителе (нумерация начинается с нуля). Первый из переданных в метод аргументов занимает место заполнителя {0}
, второй — {1}
, и так далее. При этом мы можем использовать одно и то же число в нескольких заполнителях.
Приведенный ниже код:
name = 'James'
surname = 'Bond'
result = 'My name is {1}, {0} {1}'.format(name, surname)
print(result)
выводит:
My name is Bond, James Bond
При подстановке именованных аргументов в заполнителе необходимо указать имя аргумента, значение которого требуется поместить в строку вместо заполнителя. При этом мы можем использовать одно и то же имя в нескольких заполнителях. Если имя аргумента не указано в заполнителе, возбуждается исключение KeyError
.
Приведенный ниже код:
result = 'My name is {surname}, {name} {surname}'.format(name='James', surname='Bond')
print(result)
выводит:
My name is Bond, James Bond
Также допускается одновременная подстановка в строку позиционных и именованных аргументов.
Приведенный ниже код:
name = 'James'
result = 'My name is {surname}, {0} {surname}'.format(name, surname='Bond')
print(result)
выводит:
My name is Bond, James Bond
Основным недостатком форматирования строк с помощью метода format()
является избыточность кода в случаях, когда требуется подставить в строку большое количество значений.
f-строки
В Python 3.6 появился новый способ форматирования строк — f-строки (formatted string literals, f-strings). F-строка представляет собой строку с префиксом 'f'
или 'F'
, которая может содержать заполнители {}
. В каждый заполнитель помещаются переменные или выражения, значения которых объединяются со строковой частью f-строки.
Приведенный ниже код:
name = 'James'
surname = 'Bond'
result = f'My name is {surname}, {name.upper()} {surname.upper()}'
print(result)
выводит:
My name is Bond, JAMES BOND
Если в заполнитель f-строки требуется подставить строковый литерал напрямую, кавычки f-строки и подставляемого строкового литерала должны быть различны (это ограничение действует до версии Python 3.12).
Приведенный ниже код:
print(f'My name is {"Bond"}, {"James"} {"Bond"}')
выводит:
My name is Bond, James Bond
Фигурные скобки {}
в f-строках являются специальными символами для обозначения заполнителей. Для вывода в итоговой строке самих фигурных скобок их необходимо экранировать. Для этого используется экранирование двойными фигурными скобками {{}}
.
Приведенный ниже код:
num = 10
print(f'{{num}}')
выводит:
{num}
Обратите внимание, что выражение внутри {{}}
не вычисляется. Если нужно вычислить значение выражения, необходимо использовать тройные фигурные скобки {{{}}}
.
Приведенный ниже код:
num = 10
print(f'{{{num}}}')
выводит:
{10}
Для вывода двух фигурных скобок {{}}
в f-строке необходимо использовать 4 фигурные скобки {{{{}}}}
и еще {}
для вычисления выражения. В общем виде количество экранирующих фигурных скобок вычисляется согласно правилу: четное количество {}
+ {}
, если нужно вычислить выражение.
Приведенный ниже код:
num = 10
print(f'{{{{num}}}}')
print(f'{{{{{num}}}}}')
выводит:
{{num}}
{{10}}
Если в строковой части f-строки содержатся управляющие последовательности, то для вывода в явном виде их необходимо экранировать с помощью символа обратной косой черты \
.
Приведенный ниже код:
print(f'\\a\\b\\f\\n\\r\\t\\v')
выводит:
\a\b\f\n\r\t\v
Также возможно использование сочетания f-строк и сырых (raw) строк.
Приведенный ниже код:
print(fr'\a\b\f\n\r\t\v')
выводит:
\a\b\f\n\r\t\v
F-строки имеют ряд преимуществ по сравнению с другими способами форматирования строк: они работают быстрее, имеют простой и гибкий синтаксис, более читаемы и менее подвержены ошибкам. Кроме того, возможности f-строк постепенно расширяются с выходом новых версий Python.
Например, в Python 3.12 было снято ограничение на использование одинаковых кавычек в f-строках и их заполнителях.
Приведенный ниже код:
print(f'My name is {'Bond'}, {'James'} {'Bond'}')
в Python 3.11 и ранее приводит к возбуждению исключения:
SyntaxError: f-string: expecting '}'
в то время как в Python 3.12 выводит:
My name is Bond, James Bond
Также в Python 3.12 было снято ограничение на использование в заполнителях f-строк символа \
.
Приведенный ниже код:
print(f'{"\n".join(["James", "Bond"])}')
в Python 3.11 и ранее приводит к возбуждению исключения:
SyntaxError: f-string expression part cannot include a backslash
в то время как в Python 3.12 выводит:
James
Bond
Начиная с Python 3.6 для форматирования строк в большинстве случаев рекомендуется использовать именно f-строки. ?
Подведем итоги
Мы рассмотрели основные способы форматирования строк в Python — оператор %
, строковый метод format()
и f-строки. В настоящее время любой из них можно использовать на практике. Однако %
-форматирование считается устаревшим. Если вы пишите код на Python 3.5 и ниже, используйте для форматирования строк строковый метод format()
. В программах на Python 3.6 и выше используйте для форматирования f-строки.
Присоединяйтесь к нашему телеграм-каналу, будет интересно и познавательно!
❤️ Happy Pythoning! ?
Комментарии (26)
tonylenc
16.07.2024 08:34+7Хотя f-строки часто удобнее и читабельнее для простых случаев, метод
format()
предоставляет некоторые дополнительные возможности, такие как совместимость с более старыми версиями Python (а f-строки работают только с версии 3.6) или возможности распаковки коллекций.Например, можно распаковывать коллекции прямо при передаче аргументов:
person = ('Alice', 'Moscow', 21)
print("My name is {}. I'm from {} and I'm {} years old.".format(*person))
# My name is Alice. I'm from Moscow and I'm 21 years old.
Или в случае со словарём:
person = {'name': 'Alice', 'city': 'Moscow', 'age': 21}
print("My name is {name}. I'm from {city} and I'm {age} years old.".format(**person))
# My name is Alice. I'm from Moscow and I'm 21 years old.
domix32
16.07.2024 08:34+3Сомнительная фича эти распаковки. Как минимум читать откуда ноги растут на порядок сложнее, а с учётом отсутвия жёсткой типизации ещё и ошибок можно огрести, оптимизировать или рефакторить такое тоже заметно сложнее.
milssky
16.07.2024 08:34+1Для шаблона строки почти всегда используют константу с нормальным именем. И распаковка становится очень удобной штукой
wildmathing
не знал про фигурные скобки в f строках)