62 Глава 2 •
Шаблоны для чистого Python
№ 4 . Шаблонные
строки
Еще один прием форматирования строк в Python представлен шаблон-
ными строками. Этот механизм более простой и менее мощный, но в не-
которых случаях он
может оказаться именно тем, что вы ищете.
Давайте взглянем на простой пример приветствия:
>>>
from string import Template
>>> t = Template('Эй, $name!')
>>> t.substitute(name=name)
'Эй, Боб!'
Здесь вы видите, что нам приходится импортировать класс
Template
из
встроенного модуля Python
string
. Шаблонные строки не являются
ключевым функциональным свойством языка, но они обеспечиваются
модулем стандартной библиотеки.
Еще одно отличие состоит в том, что шаблонные строки не допускают
спецификаторы формата. Поэтому, чтобы заставить пример со строковой
ошибкой работать, мы должны сами преобразовать целочисленный код
ошибки в шестнадцатеричное строковое значение:
>>> templ_string = 'Эй, $name! Вот ошибка $error!'
>>> Template(templ_string).substitute(
... name=name, error=hex(errno))
'Эй, Боб! Вот ошибка 0xbadc0ffee!'
Пример сработал отлично, но вы, вероятно, интересуетесь, в каких случа-
ях использовать шаблонные строки в программах на Python. По-моему,
самый лучший вариант применения шаблонных строк наступает тогда,
когда вы обрабатываете форматные строки, сгенерированные пользова-
телями программы. Благодаря их уменьшенной сложности, шаблонные
строки являются более безопасным вариантом выбора.
Более сложные мини-языки форматирования для других приемов фор-
матирования строк могут вносить уязвимости в ваши программы с точки
зрения безопасности. Например, форматные строки могут получать до-
ступ к произвольным переменным в программе.
2 .5 . Шокирующая правда о форматировании
строковых значений 63
Это означает, что если злонамеренный пользователь может передать
форматную строку, то он также может потенциально раскрыть секретные
ключи и другую ценную информацию! Вот простое доказательство идеи
о том, как такая атака могла бы использоваться:
>>> SECRET = 'это – секрет'
>>> class Error:
... def __init__(self):
... pass
>>> err = Error()
>>> user_input = '{error.__init__.__globals__[SECRET]}'
# Ой-ей-ей...
>>> user_input.format(error=err)
'это – секрет'
Заметили, как гипотетический взломщик смог извлечь нашу секретную
строку, обратившись из форматной строки к словарю
__globals__
? Жутко,
да! Шаблонные строки закрывают это направление атаки, и это делает их
более безопасным выбором, если вы обрабатываете форматные строки,
генерируемые из
данных, вводимых пользователем:
>>> user_input = '${error.__init__.__globals__[SECRET]}'
>>> Template(user_input).substitute(error=err)
ValueError:
"Invalid placeholder in string: line 1, col 1"
Какой метод форматирования строк мне использовать?
Я вполне понимаю, что, имея такой широкий выбор способов форматиро-
вания своих строковых значений в Python, вы можете испытывать заме-
шательство. Здесь не помешало бы соорудить какую-нибудь инфографику
в виде блок-схемы.
Но я этого не сделаю. Вместо этого я попытаюсь все свести к простому
эмпирическому правилу,
которое я применяю, когда пишу на Python.
Поехали! Вы можете применять это эмпирическое правило в любой ситу-
ации, когда вы испытываете затруднения при принятии решения, какой
метод
форматирования использовать; все зависит от обстоятельств.