Часто при написании кода на Python нам требуется представить объект определенным образом или включить значения каких-либо выражений внутрь строки. Для этого мы можем использовать форматирование строк. При этом в Python существуют сразу три способа форматирования строк:

  • оператор %  

  • строковый метод format()  

  • f-строки

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

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

Оператор %

Оператор % является первым способом форматирования строк, который появился в Python. Он был заимствован из языка C, на котором написан основной интерпретатор Python, поэтому данный способ форматирования строк также называют форматированием в стиле С.

Для форматирования с помощью оператора % необходимо слева от оператора указать строку с заполнителем %s, а справа — подставляемое в нее значение.

Приведенный ниже код:

print('My name is %s' % 'James')

выводит:

My name is James

Символ s в заполнителе обозначает преобразование подставляемого значения в формат строки. Мы можем использовать и другие форматы, наиболее важные из которых приведены в таблице ниже:

формат

значение

d

целое число

f

число с плавающей точкой

o

число в восьмеричной системе счисления

x

число в шестнадцатеричной системе счисления

e

число в экспоненциальном формате

r

формальное строковое представление объекта (аналогично функции repr())

Например, вместо символа 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)


  1. wildmathing
    16.07.2024 08:34

    не знал про фигурные скобки в f строках)


  1. 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.


    1. domix32
      16.07.2024 08:34
      +3

      Сомнительная фича эти распаковки. Как минимум читать откуда ноги растут на порядок сложнее, а с учётом отсутвия жёсткой типизации ещё и ошибок можно огрести, оптимизировать или рефакторить такое тоже заметно сложнее.


      1. milssky
        16.07.2024 08:34
        +1

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