Форматирование строк с помощью шаблона шаблона Python

2 min


Вступление

Шаблоны Python используются для подстановки данных в строки. С помощью шаблонов мы получаем сильно настраиваемый интерфейс для подстановки строк (или интерполяции строк).

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

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

Для лучшего понимания этих тем вам потребуются некоторые базовые знания о том, как работать с классами и регулярными выражениями.

Понимание класса шаблонов Python

Питон Template класс был добавлен к string модуль начиная с Python 2.4. Этот класс предназначен для использования в качестве альтернативы встроенным опциям замещения (в основном %) для создания сложных шаблонов на основе строк и для удобной работы с ними.

Реализация класса использует регулярные выражения для соответствия общему шаблону допустимых строки шаблона, Допустимая строка шаблона, или заполнитель, состоит из двух частей:

  • $ символ
  • Действительный идентификатор Python. Идентификатор – это любая последовательность прописных и строчных букв от A до Z, подчеркивание (_) и цифры от 0 до 9. Идентификатор не может начинаться с цифр и не может быть ключевым словом Python.

В строке шаблона $name и $age будут считаться действительными заполнителями.

Чтобы использовать Питон Template Класс в нашем коде, нам нужно:

  1. импорт Template от string модуль
  2. Создайте правильную строку шаблона
  3. Instantiate Template используя строку шаблона в качестве аргумента
  4. Выполните замену, используя метод замены

Вот основной пример того, как мы можем использовать Python Template класс в нашем коде:

>>> from string import Template
>>> temp_str = 'Hi $name, welcome to $site'
>>> temp_obj = Template(temp_str)
>>> temp_obj.substitute(name='John Doe', site='StackAbuse.com')
'Hi John Doe, welcome to StackAbuse.com'

Мы замечаем, что когда мы строим шаблон строки temp_strМы используем два заполнителя: $name и $site, $ знак выполняет фактическую замену и идентификаторы (name и site) используются для отображения заполнителей на конкретные объекты, которые нам нужно вставить в строку шаблона.

Волшебство завершается, когда мы используем метод substitute () для выполнения подстановки и построения нужной строки. Думать о substitute() как если бы мы говорили Python, пройти через эту строку, и если вы найдете $nameзатем замените его на John Doe, Продолжить поиск по строке и, если вы найдете идентификатор $site, а затем превратить его в StackAbuse.com,

Названия аргументов, которые мы передаем .substitute() необходимо сопоставить с идентификаторами, которые мы использовали в заполнителях нашей строки шаблона.

Самое важное различие между Template а остальные инструменты подстановки строк, доступные в Python, – это то, что тип аргумента не учитывается. Мы можем передать любой тип объекта, который может быть преобразован в допустимую строку Python. Template Класс автоматически преобразует эти объекты в строки, а затем вставляет их в окончательную строку.

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

Строка шаблона

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

В соответствии с PEP 292 – Простые строковые заменыследующие правила применяются для использования $ войти в заполнители:

  1. $$ это побег; он заменяется одним $
  2. $identifier называет замещающий заполнитель, соответствующий ключу сопоставления «идентификатора». По умолчанию «идентификатор» должен записывать идентификатор Python, как определено в http://docs.python.org/reference/lexical_analysis.html#identifiers-and-keywords, Первый неидентифицирующий символ после $ символ завершает эту спецификацию заполнителя.
  3. ${identifier} эквивалентно $identifier, Требуется, когда действительные идентификаторы следуют за заполнителем, но не являются частью заполнителя, например "${noun}ification", (Источник)

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

Начнем с примера того, как мы можем избежать $ подписать. Предположим, мы имеем дело с валютами, и нам нужно иметь знак доллара в наших результирующих строках. Мы можем удвоить $ Войдите, чтобы экранировать себя в строке шаблона следующим образом:

>>> budget = Template('The $time budget for investment is $$$amount')
>>> budget.substitute(time='monthly', amount='1,000.00')
'The monthly budget for investment is $1,000.00'

Обратите внимание, что нет необходимости добавлять дополнительный пробел между экранированным знаком и следующим заполнителем, как мы это делали в $$$amount, Шаблоны достаточно умны, чтобы избежать $ Подпишите правильно.

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

>>> template = Template('$what, $who!')
>>> template.substitute(what='Hello', who='World')
'Hello, World!'

Здесь оба заполнителя формируются с использованием допустимых идентификаторов Python (what и who). Также обратите внимание, что, как указано во втором правиле, первый неидентифицирующий символ завершает заполнитель, как вы можете видеть в $who! где персонаж ! не часть заполнителя, а окончательная строка.

Могут быть ситуации, когда нам нужно частично заменить слово в строке. Вот почему у нас есть второй вариант для создания заполнителя. Третье правило гласит, что ${identifier} эквивалентно $identifier и должен использоваться, когда действительные идентификаторы следуют за заполнителем, но не являются частью самого заполнителя.

Предположим, нам нужно автоматизировать создание файлов, содержащих коммерческую информацию о продуктах нашей компании. Файлы называются в соответствии с шаблоном, который включает в себя код продукта, имя и производственный пакет, все они разделены подчеркиванием (_) персонаж. Рассмотрим следующий пример:

>>> filename_temp = Template('$code_$product_$batch.xlsx')
>>> filename_temp.substitute(code='001', product='Apple_Juice', batch='zx.001.2020')
Traceback (most recent call last):
  ...
KeyError: 'code_'

поскольку _ является допустимым идентификатором Python, наша строка шаблона не работает должным образом и Template поднимает KeyError, Чтобы исправить эту проблему, мы можем использовать обозначение в скобках (${identifier}) и создайте наши заполнители следующим образом:

>>> filename_temp = Template('${code}_${product}_$batch.xlsx')
>>> filename_temp.substitute(code='001', product='Apple_Juice', batch='zx.001.2020')
'001_Apple_Juice_zx.001.2020.xlsx'

Теперь шаблон работает правильно! Это потому, что скобки правильно отделяют наши идентификаторы от _ персонаж. Стоит отметить, что нам нужно использовать только условные обозначения для code и product и не для batch поскольку . персонаж, который следует batch недопустимый символ идентификатора в Python.

Наконец, строка шаблона сохраняется в template свойство экземпляра. Давайте вернемся к Hello, World! пример, но на этот раз мы собираемся изменить template совсем немного:

>>> template = Template('$what, $who!')  # Original template
>>> template.template = 'My $what, $who template'  # Modified template
>>> template.template
'My $what, $who template'
>>> template.substitute(what='Hello', who='World')
'My Hello, World template'

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

Лучше всего создавать новые экземпляры Template для каждой отдельной строки шаблона мы используем в нашем коде. Таким образом, мы избежим некоторых тонких и трудно обнаруживаемых ошибок, связанных с использованием неопределенных строк шаблона.

Метод замены ()

До сих пор мы использовали substitute() метод на Template экземпляр для выполнения подстановки строк. Этот метод заменяет заполнители в строке шаблона, используя ключевые аргументы или сопоставление, содержащее пары идентификатор-значение.

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

Поскольку в предыдущих примерах мы рассмотрели использование аргументов ключевых слов, давайте теперь сосредоточимся на использовании словарей. Вот пример:

>>> template = Template('Hi $name, welcome to $site')
>>> mapping = {'name': 'John Doe', 'site': 'StackAbuse.com'}
>>> template.substitute(**mapping)
'Hi John Doe, welcome to StackAbuse.com'

Когда мы используем словари в качестве аргументов substitute()нам нужно использовать оператор распаковки словаря: **, Этот оператор будет распаковывать пары ключ-значение в ключевые аргументы, которые будут использоваться для замены соответствующих заполнителей в строке шаблона.

Распространенные ошибки шаблона

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

Например, KeyError возникает всякий раз, когда мы предоставляем неполный набор аргументов substitute(), Рассмотрим следующий код, который использует неполный набор аргументов:

>>> template = Template('Hi $name, welcome to $site')
>>> template.substitute(name='Jane Doe')
Traceback (most recent call last):
  ...
KeyError: 'site'

Если мы позвоним substitute() с набором аргументов, который не соответствует всем заполнителям в нашей строке шаблона, тогда мы получим KeyError,

Если мы используем недопустимый идентификатор Python в некоторых наших заполнителях, мы получим ValueError говорит нам, что заполнитель неверен.

Возьмите этот пример, где мы используем неверный идентификатор, $0name в качестве заполнителя вместо $name,

>>> template = Template('Hi $0name, welcome to $site')
>>> template.substitute(name='Jane Doe', site='StackAbuse.com')
Traceback (most recent call last):
  ...
ValueError: Invalid placeholder in string: line 1, col 4

Только когда Template Объект читает строку шаблона, чтобы выполнить подстановку, обнаружив неверный идентификатор. Это сразу поднимает ValueError, Обратите внимание, что 0name не является допустимым идентификатором или именем Python, поскольку начинается с цифры.

Метод safe_substitute ()

Питон Template В классе есть второй метод, который мы можем использовать для подстановки строк. Метод называется safe_substitute(), Работает аналогично substitute() но когда мы используем неполный или несоответствующий набор аргументов, метод не поднимает KeyError,

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

Вот как safe_substitute() работает с неполным набором аргументов (site будет отсутствовать):

>>> template = Template('Hi $name, welcome to $site')
>>> template.safe_substitute(name='John Doe')
'Hi John Doe, welcome to $site'

Здесь мы первый звонок safe_substitute() используя неполный набор аргументов. Полученная строка содержит оригинальный заполнитель $site, но нет KeyError Поднялся.

Настройка класса шаблона Python

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

В этом разделе мы расскажем, как настроить некоторые из наиболее важных атрибутов класса и как это влияет на общее поведение нашего Template объекты. Давайте начнем с атрибута класса .delimiter,

Использование другого разделителя

Атрибут класса delimiter содержит символ, используемый в качестве начального символа заполнителя. Как мы уже видели, его значение по умолчанию $,

С Питона Template класс предназначен для наследования, мы можем подкласс Template и измените значение по умолчанию delimiter переопределив это. Взгляните на следующий пример, где мы переопределяем разделитель для использования # вместо того $:

from string import Template
class MyTemplate(Template):
    delimiter = "https://stackabuse.com/#"

template = MyTemplate('Hi #name, welcome to #site')
print(template.substitute(name='Jane Doe', site='StackAbuse.com'))

# Output:
# 'Hi Jane Doe, welcome to StackAbuse.com'

# Escape operations also work
tag = MyTemplate('This is a Twitter hashtag: ###hashtag')
print(tag.substitute(hashtag='Python'))

# Output:
# 'This is a Twitter hashtag: #Python'

Мы можем использовать наши MyTemplate класс так же, как мы используем обычный Python Template учебный класс. Тем не менее, теперь мы должны использовать # вместо того $ строить наши заполнители. Это может быть удобно, когда мы работаем со строками, которые обрабатывают много знаков доллара, например, когда мы имеем дело с валютами.

Заметка: Делать не заменить delimiter с регулярным выражением. Класс шаблона автоматически экранирует разделитель. Поэтому, если мы используем регулярное выражение как delimiter весьма вероятно, что наш обычай Template не будет работать правильно.

Изменение того, что квалифицируется как идентификатор

idpattern Атрибут class содержит регулярное выражение, которое используется для проверки второй половины заполнителя в строке шаблона. Другими словами, idpattern подтверждает, что идентификаторы, которые мы используем в наших заполнителях, являются действительными идентификаторами Python. Значение по умолчанию idpattern является r'(?-i:[_a-zA-Z][_a-zA-Z0-9]*)',

Мы можем подкласс Template и использовать наш собственный шаблон регулярного выражения для idpattern, Предположим, что нам нужно ограничить идентификаторы именами, которые не содержат подчеркивания (_) ни цифры ([0-9]). Для этого мы можем переопределить idpattern и удалите эти символы из шаблона следующим образом:

from string import Template
class MyTemplate(Template):
    idpattern = r'(?-i:[a-zA-Z][a-zA-Z]*)'

# Underscores are not allowed
template = MyTemplate('$name_underscore not allowed')
print(template.substitute(name_underscore='Jane Doe'))

Если мы запустим этот код, мы получим эту ошибку:

Traceback (most recent call last):
    ...
KeyError: 'name'

Мы можем подтвердить, что цифры также не разрешены:

template = MyTemplate('$python3 digits not allowed')
print(template.substitute(python3='Python version 3.x'))

Ошибка будет:

Traceback (most recent call last):
    ...
KeyError: 'python'

Так как подчеркивание и цифры не включены в наш обычай idpattern, Template Объект применяет второе правило и разбивает местозаполнитель первым неидентификационным символом после $, Вот почему мы получаем KeyError в каждом случае.

Создание расширенных шаблонных подклассов

Могут быть ситуации, когда нам нужно изменить поведение Python Template класс, но превосходящий delimiter, idpatternили обоих недостаточно. В этих случаях мы можем пойти дальше и переопределить pattern Атрибут класса для определения совершенно нового регулярного выражения для нашего Template подклассы.

Если вы решили использовать совершенно новое регулярное выражение для pattern, тогда вам нужно предоставить регулярное выражение с четырьмя именованными группами:

  1. escaped соответствует escape-последовательности для разделителя, как в $$
  2. named соответствует разделителю и действительному идентификатору Python, как в $identifier
  3. braced соответствует разделителю и действительному идентификатору Python с использованием фигурных скобок, как в ${identifier}
  4. invalid соответствует другим плохо сформированным разделителям, как в $0site

pattern Свойство содержит скомпилированный объект регулярного выражения. Однако можно проверить исходную строку регулярного выражения, открыв pattern атрибут pattern свойство. Проверьте следующий код:

>>> template = Template('$name')
>>> print(template.pattern.pattern)
$(?:
    (?P$) |   # Escape sequence of two delimiters
    (?P(?-i:[_a-zA-Z][_a-zA-Z0-9]*))      |   # delimiter and a Python identifier
    {(?P(?-i:[_a-zA-Z][_a-zA-Z0-9]*))}   |   # delimiter and a braced identifier
    (?P)              # Other ill-formed delimiter exprs
  )

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

Выполнение кода с помощью eval () и exec ()

Замечания: Встроенные функции eval() и exec() может иметь важные последствия для безопасности при использовании со злонамеренным вводом. Используйте с осторожностью!

Этот последний раздел предназначен, чтобы открыть вам глаза на то, как мощный Python Template класс может быть, если мы используем его вместе с некоторыми встроенными функциями Python, такими как eval() и exec(),

eval() Функция выполняет одно выражение Python и возвращает его результат. exec() Функция также выполняет выражение Python, но никогда не возвращает его значение. Вы обычно используете exec() когда вас интересует только побочный эффект выражения, например, изменение значения переменной.

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

Для первого примера мы будем использовать шаблон вместе с eval() динамически создавать списки с помощью понимания списка:

>>> template = Template('[$exp for item in $coll]')
>>> eval(template.substitute(exp='item ** 2', coll='[1, 2, 3, 4]'))
[1, 4, 9, 16]
>>> eval(template.substitute(exp='2 ** item', coll='[3, 4, 5, 6, 7, 8]'))
[8, 16, 32, 64, 128, 256]
>>> import math
>>> eval(template.substitute(expression='math.sqrt(item)', collection='[9, 16, 25]'))
[3.0, 4.0, 5.0]

Наш шаблонный объект в этом примере содержит основной синтаксис понимания списка. Начиная с этого шаблона, мы можем динамически создавать списки, заменяя заполнители действительными выражениями (exp) и коллекции (coll). В качестве последнего шага мы запускаем понимание, используя eval(),

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

from string import Template

_class_template = """
class ${klass}:
    def __init__(self, name):
        self.name = name

    def ${method}(self):
        print('Hi', self.name + ',', 'welcome to', '$site')
"""

template = Template(_class_template)
exec(template.substitute(klass='MyClass',
                         method='greet',
                         site='StackAbuse.com'))

obj = MyClass("John Doe")
obj.greet()

Здесь мы создаем строку шаблона для хранения полнофункционального класса Python. Позже мы можем использовать этот шаблон для создания разных классов, но с разными именами в соответствии с нашими потребностями.

В таком случае, exec() создает реальный класс и переносит его в наше текущее пространство имен. С этого момента мы можем свободно использовать класс, как мы это делаем с любым обычным классом Python.

Несмотря на то, что эти примеры довольно просты, они показывают, насколько мощный Python Template Класс может быть и как мы можем использовать его для решения сложных задач программирования в Python.

Вывод

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

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

Имея эти знания под рукой, мы находимся в лучшем состоянии для эффективного использования Python Template класс для выполнения интерполяции или подстановки строк в нашем коде.


0 Comments

Ваш адрес email не будет опубликован. Обязательные поля помечены *