1 – “Старый стиль” форматирования строк

Строки в Python имеют уникальную встроенную операцию, к которой можно получить доступ с помощью оператора - %. Это ярлык, который позволяет легко создавать позиционное форматирование. Если вы когда-либо работали с функцией printf в C, вы сразу узнаете, как это работает. Вот простой пример:

>>> 'Привет, %s' %'Олег' 
'Привет, Олег'

В примере выше используется спецификатор формата %s, чтобы указать python’у, где заменить значение имени, представленного в виде строки. Это называется форматированием строк «старого стиля».

В python для форматирования строк таким стилем имеются и другие спецификаторы формата. Например, можно преобразовать числа в шестнадцатеричную нотацию или добавить пробелы для создания красиво отформатированных таблиц и отчетов.

В следующем примере используется спецификатор формата %x, чтобы преобразовать значение int в строку и представить его как шестнадцатеричное число:

»> ‘%x’ %’badc0ffee’ ‘badc0ffee’

Синтаксис форматирования строки ”старым стилем” изменяется незначительно, если вы хотите сделать несколько замен в одной строке. Поскольку оператор % принимает только один аргумент, необходимо обернуть правую часть в кортеж, например:

 >>> 'Привет %s, у нас 0x%x ошибка!' % (name, errno) 
 'Привет Олег, у нас 0xbadc0ffee ошибка!'

Также можно ссылаться на подстановки переменных по имени в форматируемой строке, если передать сопоставление оператору %:

>>> 'Привет %(name)s, у нас 0x%(errno)x ошибка!' %{ ... "name": name, "errno": errno }
'Привет Олег, у нас 0xbadc0ffee ошибка!'

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

Может показаться странным, почему это форматирование в стиле printf называется форматированием строки «старого стиля». Технически этот стиль форматирования строк заменен форматированием «нового стиля», о котором будет сказано ниже. Но в то же время форматирование «старого стиля» фактически не устарело. Такой стиль по-прежнему поддерживается в самых последних версиях Python.

2 – Форматирование строк “новым стилем”

В Python 3 был представлен новый способ форматирования строк, который также был позже включен в Python 2.7. Это форматирование строки «нового стиля» избавилось от оператора % и делает синтаксис форматирования строк более регулярным. Теперь форматирование обрабатывается вызовом функции format () для строкового объекта.

Можно использовать функцию format() для простого форматирования позиционирования, как и при форматировании «старым стилем»:

>>> 'Привет, {}'.format(name) 
'Привет, Олег'

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

 >>> 'Привет {name}, у нас 0x{errno:x} ошибка!'
 .format( ... name=name, errno=errno)
'Привет Олег, у нас 0xbadc0ffee ошибка!'

Это также показывает, что синтаксис для форматирования переменной int как шестнадцатеричной строки изменился. Теперь нам нужно передать спецификацию формата, добавив суффикс «:x» после имени переменной.

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

В Python 3 это форматирование строки с помощью «нового стиля» предпочтительнее, чем форматирование в стиле %. Однако, начиная с Python 3.6, есть еще лучший способ форматирования строк. Об этом в следующем разделе.

3 – Интерполяция строкового литерала (Python 3.6+)

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

>>> f'Привет, {name}!' 
'Привет, Олег!'

Этот новый синтаксис форматирования является довольно мощным. Поскольку вы можете вставлять произвольные выражения python, вы можете даже выполнить внутристрочную арифметику с ним, например:

>>> a = 5
>>> b = 10
>>> f'Пять плюс десять равно {a + b} а не {2 * (a + b)}.'
'Пять плюс десять равно  15 а не 30.'

В основе способа форматированных строковых литералов лежит функция парсера Python, которая преобразует f-строки в ряд строковых констант и выражений. Затем они соединяются, чтобы представить финальную строку.

Допустим, что у нас есть следующая функция greet (), содержащая f-строку:

 >>> def greet(name, question):
... 	return f"Привет, {name}! Как {question}?" 
...

>>> greet('Олег', 'дела') "Привет, Олег! Как дела?"

Если разобрать функцию и проверить, что происходит в при ее выполнении, можно увидеть, что f-строка в функции преобразуется во что - то похожее на следующее:

>>> def greet(name, question):
... 	return ("Привет, " + name + "! Как " +
				question + "?")

Строковые литералы также поддерживают существующий синтаксис строки формата str.метод format(). Это позволяет решить те же проблемы форматирования, которые мы обсуждали в предыдущих двух разделах:

»> f”Привет {name}, у нас {errno:#x} ошибка!” “Привет Олег, у нас 0xbadc0ffee ошибка!”

Python’s new Formatted String Literals are similar to the JavaScript Template Literals added in ES2015. I think they’re quite a nice addi- tion to the language, and I’ve already started using them in my day- to-day Python 3 work. You can learn more about Formatted String Literals in the official Python documentation.15

4 – Шаблон строк

Еще один метод форматирования строк в python - шаблон строк. Этот метод проще и имеет менее мощный механизм, но в некоторых случаях это может быть именно то, что вы искали.

Давайте рассмотрим простой пример приветствия:

>>> from string import Template 
>>> t = Template('Привет, $name!') 
>>> t.substitute(name=name) 
'Привет, Олег!'

Вы видите здесь, что нам нужно импортировать класс шаблона из встроенного модуля строки python. Строки шаблона не являются основной функцией языка, но они предоставляются модулем в стандартной библиотеке.

Другое отличие состоит в том, что шаблоны строк не допускают спецификаторы формата. Таким образом, чтобы заставить наш пример строки с номером ошибки работать, нам нужно преобразовать номер ошибки int в шестнадцатеричную строку:

>>> templ_string = 'Привет $name, у нас $error ошибка!' 
>>> Template(templ_string).substitute(
... name=name, error=hex(errno))
'Привет Олег, у нас 0xbadc0ffee ошибка!'

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

Более сложное форматирование на мини-языках других методов форматирования строк может привести к уязвимостям в программах. Например, форматируемые строки могут обращаться к произвольным переменным в программе.

Это означает, что если злонамеренный пользователь может предоставить строку формата они также могут потенциально организовать утечки секретных ключей и другой полезную информации.

Какой-же метод форматрирования строк надо использовать?

Имея так много способов для форматирования строк в python, сделать правильный выбор может показаться очень непросто.

Лучше всего для правильного применения того или иного способа форматирования строк попробовать руководствоваться простым правилом:

Если строки формата предоставляются Пользователем, используйте строки шаблона, чтобы избежать проблем безопасности. В противном случае используйте интерполяцию строк литералов, если вы используете Python 3.6+, тогда форматируйте строки “новым стилем”.

Основные выводы

• Существует несколько способов форматирования строк в python.

• Каждый метод имеет свои индивидуальные плюсы и минусы. Ваш вариант использования будет влиять на то, какой метод вы должны использовать.

• Если вы не можете решить, какой метод форматирования строк использовать, попробуйте приведенное выше правило форматирования строк.

Источник: “Python Tricks The Book” Dan Bader