PEP 750: t-строки в 3.14
Недавно ревьюил один интересный PR в CPython: в питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций. Расскажу: как и зачем.
Основная причина: использовать f строки удобно, но нет никакого АПИ для перехвата момента "вставки" или интерполяции значений. Например, при форматировании html или sql – требуется специальным образом делать escape для значений. И раньше код вида f"{template}"
представлял собой дыру в безопасности и потенциальное место для XSS.
string.templatelib.Template
Новый префикс t
не будет создавать объект str, он будет создавать объект класса string.templatelib.Template
:
>>> user = 'sobolevn'
>>> template = t"Hi, {user}"
>>> template
Template(strings=('Hi, ', ''), interpolations=(Interpolation('sobolevn', 'user', None, ''),))
>>> from string.templatelib import Template
>>> isinstance(template, Template)
True
Обратите внимание, что при создании template
– у нас не произошло форматирование сразу. Мы создали объект, у которого есть свойства strings
и interpolations
, из которых можно собрать финальную отформатированную строку.
Давайте посмотрим на примере. Допустим, мы хотим формировать URL из наших данных:
>>> domain = 'example.com'
>>> query = 'python string formatting is too complex'
>>> template = t'https://{domain}?q={query}'
И сам код логики форматирования, где мы будем вставлять значения разным способом. Если у нас шаблон query, то мы будем использовать quote_plus
для его форматирования. Остальные значения – будем вставлять как есть:
>>> from string.templatelib import Template, Interpolation
>>> from urllib.parse import quote_plus
>>> def format_url(template: Template) -> str:
... parts = []
... for part in template:
... match part:
... case str() as s: # regular string
... parts.append(s)
... case Interpolation(value, expression='query'):
... parts.append(quote_plus(value))
... case Interpolation(value):
... parts.append(value)
... return ''.join(parts)
И вот результат:
>>> format_url(template)
'https://example.com?q=python+string+formatting+is+too+complex'
Только теперь наш Template
был отформатирован. Нами. Ручками.
У нас есть полный контроль за процессом форматирования. Вот в чем суть данного ПЕПа.
Фичи одной строкой
Работает
=
как обычно вf
строках:t'{user=}'
Есть привычные определители формата:
!r
,!s
,.2f
, тдt строки можно конкатенировать:
t'Hello' + t' , world!'
иt'Hello, ' + 'world'
Поддерживается режим raw строк:
rt"Hi \n!"
Как устроено внутри?
Интересные места имплементации:
Новые классы
Template
иInterpolation
написанные на CНовый байткод
BUILD_INTERPOLATION
иBUILD_TEMPLATE
>>> import dis
>>> user = 'sobolevn'
>>> dis.dis('t"Hi, {user}"')
0 RESUME 0
1 LOAD_CONST 2 (('Hi, ', ''))
LOAD_NAME 0 (user)
LOAD_CONST 1 ('user')
BUILD_INTERPOLATION 2
BUILD_TUPLE 1
BUILD_TEMPLATE
RETURN_VALUE
Обсуждение: как вам еще один способ форматирования строк?
Если понравилось – заходи в тг, где я рассказываю, как я делаю CPython.