Интерполяция строк в Python: изучение доступных инструментов
Интерполяция строк позволяет создавать строки путем вставки объектов в определенные места шаблона целевой строки. В Python имеется несколько инструментов для интерполяции строк, включая f-строки, метод str.format()
и оператор по модулю (%
). Модуль Python string
также предоставляет класс Template
, который можно использовать для интерполяции строк.
В этом уроке вы:
- Узнайте, как использовать f-строки для интерполяции строк eager.
- Выполните ленивую интерполяцию строк с помощью метода
str.format()
. - Изучите основы использования оператора по модулю (
%
) для интерполяции строк. - Решите, использовать ли для интерполяции f-строки или метод
str.format()
. - Создайте шаблоны для интерполяции строк с помощью
string.Template
Чтобы получить максимальную пользу от этого руководства, вы должны быть знакомы со строками Python, которые представлены классом str
.
Строковая интерполяция в Python
Иногда при работе со строками вам приходится создавать строки, используя несколько разных строковых значений. Изначально вы могли использовать оператор плюс (+
) для объединения строк в Python. Однако такой подход приводит к коду со множеством кавычек и плюсов:
>>> name = "Pythonista"
>>> day = "Friday" # Of course 😃
>>> "Hello, " + name + "! Today is " + day + "."
'Hello, Pythonista! Today is Friday.'
В этом примере вы создаете строку, используя текст и пару переменных, которые содержат строковые значения. Множество знаков плюс затрудняют чтение и написание кода. У Python должен быть лучший и более чистый способ.
Примечание. Чтобы узнать больше о конкатенации строк в Python, ознакомьтесь с руководством по эффективной конкатенации строк в Python.
Оператор по модулю (%
) стал немного лучше синтаксиса:
>>> "Hello, %s! Today is %s." % (name, day)
'Hello, Pythonista! Today is Friday.'
В этом примере вы используете оператор по модулю для вставки переменных name
и day
в строковые литералы. Процесс создания строк путем вставки в них других строк, как вы это сделали здесь, известен как интерполяция строк.
Примечание. Форматирование с помощью оператора modulo основано на форматировании printf()
, используемом в C и многих других языках программирования.
Комбинация символов %s
называется спецификатором преобразования. Они работают как поля замены. Оператор %
отмечает начало спецификатора, а буква s
является типом преобразования и сообщает оператору, что вы хотите преобразовать входные данные. объект в строку. Вы узнаете больше о спецификаторах преобразования в разделе об операторе по модулю.
Примечание. В этом уроке вы узнаете о двух разных типах интерполяции строк:
- Стремительная интерполяция
- Ленивая интерполяция
При быстрой интерполяции Python вставляет значения в строку во время выполнения в том же месте, где вы определяете строку. При ленивой интерполяции Python задерживает вставку до тех пор, пока строка действительно не понадобится. В последнем случае вы создаете шаблоны строк в одном месте кода и заполняете шаблон значениями в другом месте.
Но на операторе по модулю история не заканчивается. Позже в Python появился метод str.format()
:
>>> "Hello, {}! Today is {}.".format(name, day)
'Hello, Pythonista! Today is Friday.'
Метод интерполирует свои аргументы в целевую строку, используя поля замены, ограниченные фигурными скобками. Несмотря на то, что этот метод может создавать трудночитаемый код, он представляет собой значительное преимущество по сравнению с оператором по модулю: он поддерживает мини-язык форматирования строк.
Примечание. Форматирование строк — фундаментальная тема Python, и иногда люди думают, что форматирование и интерполяция — это одно и то же. Однако это не так. В этом уроке вы узнаете только об интерполяции. Чтобы узнать о форматировании строк и мини-языке форматирования, ознакомьтесь с руководством Python Format Mini-Language for Tidy Strings.
Python продолжает развиваться, и каждая новая версия содержит новые интересные функции. В Python 3.6 появились форматированные строковые литералы, или для краткости f-строки:
>>> f"Hello, {name}! Today is {day}."
'Hello, Pythonista! Today is Friday.'
Фа-строки предлагают более читаемый и понятный способ создания строк, включающих другие строки. Чтобы создать f-строку, вы должны поставить перед ней префикс f
или F
. Опять же, фигурные скобки ограничивают поля замены.
Примечание. Чтобы узнать больше о f-строках, ознакомьтесь с руководством Python по F-строкам для интерполяции и форматирования строк.
F-строки, вероятно, в настоящее время являются самым популярным инструментом интерполяции в Python. Они читаются, быстро пишутся и эффективны. Итак, вы начнете с f-строк и того, как их использовать для создания новых строк с помощью интерполяции.
Использование литералов F-строки для создания строк
Для большинства случаев использования интерполяции f-строки, вероятно, являются лучшим выбором, если вы используете Python 3.6 или более позднюю версию. Их синтаксис читабелен и краток. Кроме того, они будут работать быстрее, чем другие инструменты.
Один из случаев, когда f-строки не подходят, — это когда вам нужно выполнить ленивую интерполяцию. Другими словами, когда вам нужно создать шаблон строки и вставить компоненты позже в зависимости от выполнения кода. В этом случае Python выбирает вариант отложенного выполнения и откладывает обработку значения, возвращаемого выражением, до тех пор, пока это значение не понадобится.
Еще один момент, о котором следует помнить, — это безопасность. Поскольку f-строки оцениваются во время выполнения, они потенциально могут подвергнуть ваше приложение атакам путем внедрения кода, если вы не проведете тщательную очистку ввода пользователей перед интерполяцией.
В следующих разделах вы узнаете, как использовать f-строки для интерполяции строк eager в Python.
Интерполяция значений в F-строках
Используя f-строки, вы можете интерполировать переменные и выражения непосредственно в строки. Затем, когда Python выполняет f-строку, содержимое переменной или результат выражения будут интерполированы в литерал f-строки для построения окончательной строки:
>>> x = 5
>>> y = 10
>>> f"The sum of {x} and {y} is {x + y}."
'The sum of 5 and 10 is 15.'
В этом примере у вас есть две переменные: x
и y
. Затем вы создаете литерал f-строки с тремя полями замены. Первые два поля содержат переменные, а третье поле содержит выражение.
Важно отметить, что Python оценивает f-строки во время выполнения. Итак, в этом примере x
, y
и x + y
оцениваются и интерполируются в строковый литерал, когда Python выполняет строку кода. содержащий f-строку.
В f-строку можно встроить практически любое выражение Python, например арифметические выражения, выражения сравнения и логические выражения. Вы также можете использовать функции и вызовы методов и даже понимания или другие более сложные выражения:
>>> import math
>>> radius = 16
>>> f"The area of your circle is {math.pi * radius ** 2}"
'The area of your circle is 804.247719318987'
>>> name = "Pythonista"
>>> site = "real python"
>>> f"Hello, {name.upper()}! Welcome to {site.title()}!"
'Hello, PYTHONISTA! Welcome to Real Python!'
>>> f"{[2**n for n in range(3, 9)]}"
'[8, 16, 32, 64, 128, 256]'
В первой f-строке вы встраиваете математическое выражение в поле замены. Во втором примере вы используете строковые методы .upper()
и .title()
в полях замены. Python вычисляет выражение и вызывает для вас метод. Затем он вставляет результаты в полученный литерал f-строки. В последнем примере вы создаете f-строку, которая включает в себя понимание списка. Понимание создает новый список степеней 2
.
Примечание. f-строки Python по умолчанию преобразуют интерполированные значения в строки:
>>> f"The number is {42}"
'The number is 42'
>>> f"Pi {3.14}"
'Pi 3.14'
В этих примерах вы интерполируете числовые значения в f-строку. Python преобразует их в строковые объекты при выполнении интерполяции.
F-строки до версии Python 3.12 имели несколько ограничений, которые необходимо учитывать при работе с ними. Внутри полей замены нельзя:
- Повторно используйте кавычки или разделители строк.
- Встраивайте обратные косые черты, что означает, что вы не можете использовать escape-последовательности.
- Добавьте встроенные комментарии.
- Вставлять f-строки за пределы доступных вариантов кавычек
PEP 536 перечисляет все эти ограничения. Чтобы увидеть их в действии, ознакомьтесь с разделом «F-строки имели некоторые ограничения до Python 3.12» в руководстве по предварительной версии Python 3.12.
Самодокументирование интерполированного значения
С f-строками вы можете использовать функцию, известную как самодокументируемые выражения, которая добавляет знак равенства после интерполируемой переменной или выражения. Эта функция может помочь вам отладить код. Для быстрой отладки большинство людей используют встроенную функцию print()
для проверки значения переменной или результата выражения:
>>> value = "Suspicious value"
>>> print(f"{value = }")
variable = 'Suspicious value'
>>> f"{2 + 3 = }"
'2 + 3 = 5'
Вы можете использовать переменную или выражение, за которым следует знак равенства (=
) в f-строке, чтобы создать самодокументируемое выражение. Когда Python запускает f-строку, он создает строку, подобную выражению, содержащую переменную или выражение, знак равенства и текущий результат.
В этих примерах пробелы вокруг знака равенства не требуются, но они делают вывод более читабельным.
Функция самодокументируемых выражений повышает читаемость процесса интерполяции строк и может стать отличным инструментом для быстрой отладки с помощью print()
.
Использование различных представлений строк в F-строках
Фа-строки позволяют использовать в процессе интерполяции два флага, имеющих особое значение. Эти флаги относятся к тому, как Python обрабатывает строковое представление объекта. Вот флаги и их предполагаемое значение:
!s
Интерполирует строковое представление, используя
.__str__()
!r
Интерполирует строковое представление, используя
.__repr__()
В идеале специальный метод .__str__()
должен обеспечивать удобное строковое представление объекта. Python возвращается к вызову этого метода, когда вы используете функцию str()
. Между тем, метод .__repr__()
возвращает удобное для разработчиков представление, которое вы получаете при использовании функции repr()
.
Примечание. Флаг !s
является поведением по умолчанию в f-строках, поэтому вам редко придется использовать его явно.
Чтобы проиллюстрировать, как работают эти флаги, рассмотрим следующий пример класса:
class Article:
def __init__(self, title, author, pub_date):
self.title = title
self.author = author
self.pub_date = pub_date
def __str__(self):
return (
f"Article: {self.title}\n"
f"Author: {self.author}\n"
f"Published: {self.pub_date}\n"
)
def __repr__(self):
return (
f"{type(self).__name__}("
f"title={self.title!r}, "
f"author={self.author!r}, "
f"pub_date={self.pub_date!r})"
)
Этот класс Article
имеет три атрибута экземпляра: .title
, .author
и .pub_date
. Метод .__str__()
возвращает строку, содержащую информацию о статье в удобном для пользователя формате. Это сообщение предназначено для конечных пользователей, а не для разработчиков.
Примечание. Чтобы глубже изучить методы .__str__()
и .__repr__()
, ознакомьтесь со статьей «Когда следует использовать». .__repr__()
против .__str__()
в Python?
Метод .__repr__()
возвращает строку, которая представляет собой удобное для разработчиков представление объекта. Короче говоря, представление сообщает разработчику, как был создан текущий экземпляр. В идеале разработчик должен иметь возможность скопировать это строковое представление и создать эквивалентный объект.
Теперь ваш класс готов к использованию флагов !s
и !r
:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print(f"{article!s}")
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print(f"{article!r}")
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
В первой f-строке вы используете тег !s
для интерполяции строкового представления, которое возвращает .__str__()
. Во второй f-строке вы используете флаг !r
для интерполяции удобного для разработчиков строкового представления вашего объекта. Обратите внимание, что в последнем случае результирующий строковый объект представляет собой действительный код Python, который вы можете оценить.
Создание строк с помощью метода str.format()
Если вам нужно лениво интерполировать значения в строки, то вам подойдет метод str.format()
. Этот метод является универсальным инструментом для интерполяции строк в Python. Он обеспечивает читаемый синтаксис и допускает как быструю, так и ленивую интерполяцию.
Примечание. Помните, что нетерпеливая интерполяция выполняется во время выполнения, а ленивая интерполяция — это когда вы создаете строковый шаблон и откладываете интерполяцию значений на более позднее время.
В следующих разделах вы узнаете, как использовать метод .format()
для ленивой интерполяции, поскольку в большинстве случаев для быстрой интерполяции используются f-строки.
Использование позиционных и именованных аргументов
Чтобы интерполировать объекты в строку с помощью метода .format()
, вы можете использовать три разных подхода. Вы можете использовать:
- Пустые поля замены,
{}
- Поля замены индексами, начинающимися с нуля,
{0} ... {n}
- Поля замены с именованными аргументами,
{arg_1} ... {arg_n
Чтобы проиллюстрировать, как работают эти варианты, предположим, что вам нужно автоматизировать процесс создания электронных писем для клиентов, которые покупают продукты у вашей компании. Вы можете создать шаблон электронной почты, а затем динамически интерполировать данные о клиентах:
>>> template = """
... Dear {},
...
... Thank you for your recent purchase of {}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {}
... """
>>> print(template.format("Emily", "MacBook Pro 16-inch", "John"))
Dear Emily,
Thank you for your recent purchase of MacBook Pro 16-inch.
Remember, our support team is always here to assist you.
Best regards,
John
В этом примере вы создаете шаблон электронной почты с тремя пустыми полями замены. Метод .format()
вставляет переданные значения в соответствующее поле, используя их относительное положение. Если вы хотите иметь немного больше контроля над интерполяцией значений, вы можете использовать целочисленные индексы:
>>> template = """
... Dear {0},
...
... Thank you for your recent purchase of {1}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {2}
... """
>>> print(template.format("Linda", "Samsung Galaxy S22", "Jane"))
Dear Linda,
Thank you for your recent purchase of Samsung Galaxy S22.
Remember, our support team is always here to assist you.
Best regards,
Jane
В этом примере результат аналогичен. Однако теперь вы уверены, что первый аргумент, "Линда"
, будет иметь индекс 0
, а второй аргумент - "Samsung Galaxy S22"
перейдет в индекс 1
и так далее. Этот способ обработки аргументов может быть полезен, когда исходный порядок аргументов не совпадает с порядком в конечной строке:
>>> template = """
... Dear {1},
...
... Thank you for your recent purchase of {0}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {2}
... """
>>> purchase = ("Samsung Galaxy S22", "Linda", "Jane")
>>> print(template.format(*purchase))
Dear Linda,
Thank you for your recent purchase of Samsung Galaxy S22.
Remember, our support team is always here to assist you.
Best regards,
Jane
Здесь порядок элементов в кортеже purchase
не соответствует естественному порядку в шаблоне. Итак, вы перемещаете индексы в соответствии с новым порядком и получаете желаемый результат.
Примечание. Вы также можете повторять индексы аргументов в шаблоне строки. Рассмотрим следующий пример игрушки:
>>> prefix = "re"
>>> template = "{0}-create and {0}start"
>>> template.format(prefix)
're-create and restart'
В этом примере вы используете переменную prefix
в качестве аргумента для .format()
. Вставив индекс 0
дважды в шаблон, вы также дважды вставите prefix
.
Несмотря на то, что приведенные выше параметры работают нормально, они не полностью читаемы. К счастью, есть лучший способ. Вы можете использовать аргументы ключевых слов с помощью .format()
. Вот как:
>>> template = """
... Dear {customer},
...
... Thank you for your recent purchase of {product}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {employee}
... """
>>> print(
... template.format(
... customer="Bob",
... product="Canon EOS R5",
... employee="Kate"
... )
... )
Dear Bob,
Thank you for your recent purchase of Canon EOS R5.
Remember, our support team is always here to assist you.
Best regards,
Kate
В этом обновлении вы использовали явные имена в полях замены. Эти имена соответствуют аргументам ключевого слова, которые вы использовали при вызове .format()
. Теперь ваш код выглядит гораздо более читабельным.
Наконец, также можно использовать словари для передачи метода .format()
. Предположим, вы извлекаете данные из файла CSV, который выглядит примерно так:
product,customer,employee
MacBook Pro 16-inch,Emily,John
Samsung Galaxy S22,Linda,Jane
Canon EOS R5,Bob,Kate
Вы можете использовать модуль csv
из стандартной библиотеки для обработки этого файла и загрузки его содержимого, чтобы вы могли создавать электронные письма для каждой продажи. csv.DictReader
— хороший инструмент для этой задачи. Эта программа чтения позволяет вам считывать каждую строку файла CSV в словарь. Ключами будут заголовки файлов, а значениями — значения в каждой строке.
Вот код, который вы можете использовать для выполнения этой работы:
import csv
template = """
Dear {customer},
Thank you for your recent purchase of {product}.
Remember, our support team is always here to assist you.
Best regards,
{employee}
"""
def display_emails(template, path):
with open(path) as file:
for customer in csv.DictReader(file):
print(template.format(**customer))
display_emails(template, "sales.csv")
В этом коде вы сначала импортируете csv
из стандартной библиотеки. Далее у вас есть обычный шаблон электронного письма с именами в полях замены. Имена соответствуют заголовкам в файле CSV.
Далее у вас есть функция display_emails()
. Эта функция принимает два аргумента: шаблон электронного письма и путь к файлу CSV. Внутри функции вы открываете входной файл для чтения с помощью оператора with
.
Цикл for
перебирает строки файла, используя класс DictReader
. Наконец, вы используете метод .format()
для интерполяции значений в текущей строке в шаблон электронного письма. В этом примере вы используете оператор распаковки словаря (**
) для предоставления аргументов .format()
.
Продолжайте и запустите этот сценарий из командной строки, чтобы проверить вывод.
Есть еще одно интересное поведение .format()
при его использовании со словарями. Вот небольшой пример игрушки:
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> "{one}-{two}".format(**numbers)
'1-2'
>>> "{one}-{two}-{three}".format(**numbers)
'1-2-3'
>>> "{one}-{two}-{three}-{four}".format(**numbers)
Traceback (most recent call last):
...
KeyError: 'four'
Если ключи во входном словаре соответствуют именованным аргументам в строке, интерполяция работает, даже если у вас есть неиспользуемые ключи. Если ключи не соответствуют именованным аргументам, вы получаете исключение KeyError
.
Использование различных представлений строк с помощью .format()
Как и в случае с f-строками, вы также можете использовать флаги !s
и !r
с помощью .format()
для вставки объектов в ваши строки с помощью различные представления строк. При повторном использовании класса Article
из раздела «Использование различных представлений строк в F-строках» приведены два примера, показывающие, как работают флаги:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print("{article!s}".format(article=article))
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print("{article!r}".format(article=article))
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
Опять же, флаг !s
позволяет вам использовать удобное строковое представление рассматриваемого объекта. Напротив, флаг !r
позволяет использовать представление, удобное для разработчиков. Вы решите, какой флаг использовать в своем коде, учитывая целевую аудиторию вашего кода.
Использование оператора по модулю (%
) для интерполяции
Использование оператора по модулю (%
) для интерполяции строк в современном Python в значительной степени устарело. Однако этот инструмент по-прежнему работает, и вы, вероятно, найдете устаревший код, который его использует. Итак, полезно знать, как это работает.
Примечание. В современном Python вы часто будете видеть использование f-строк и использовать их для интерполяции строк. Это связано с тем, что f-строки читабельны, понятны и быстры. Однако для некоторых случаев использования существуют лучшие решения. Иногда вам необходимо выполнить ленивую интерполяцию, и в этом случае рекомендуемым инструментом является метод .format()
. Таким образом, вы, скорее всего, полностью проигнорируете оператор по модулю при интерполяции строк.
Оператор по модулю (%
) — старейший инструмент для интерполяции строк в Python. Несмотря на то, что вы можете использовать этот оператор как для быстрой, так и для ленивой интерполяции строк, синтаксис мог бы быть более читабельным и понятным.
Вам нужно вставить спецификаторы преобразования в ваши строки, а затем использовать оператор по модулю для интерполяции желаемых значений:
>>> x = 5
>>> y = 10
>>> "The sum of %d and %d is %d." % (x, y, x + y)
'The sum of 5 and 10 is 15.'
Комбинация символов, начинающаяся со знака процента (%
), называется спецификатором преобразования. В этом примере вы использовали спецификатор %d
, что означает, что вы хотите преобразовать десятичное целое число со знаком в строку. Спецификаторы преобразования работают как поля замены для оператора по модулю.
Примечание. Оператор по модулю — единственный инструмент интерполяции, который позволяет интерполировать значения в объекты bytes
:
>>> name = b"Pythonista"
>>> b"Hello, %b!" % name
b'Hello, Pythonista!'
Вы не можете выполнить этот тип интерполяции с помощью f-строк, поскольку синтаксис fb""
или bf""
недопустим. Метод .format()
не допускает такого типа интерполяции, поскольку объекты bytes
не имеют этого метода.
Чтобы выполнить ленивую интерполяцию, вы можете сделать что-то вроде следующего:
>>> template = "The sum of %d and %d is %d."
>>> template % (x, y, x + y)
'The sum of 5 and 10 is 15.'
В этом примере вы создаете строку шаблона с обязательными полями замены. Затем вы используете оператор по модулю для интерполяции значений в шаблон позже в вашем коде. Эта практика позволяет вам повторно использовать строку шаблона в нескольких разных частях вашего кода.
Примечание. Python предоставляет множество других спецификаторов формата для оператора по модулю. Полный список см. в разделе «Форматирование строк в стиле printf» документации Python.
Чтобы узнать о других способах использования оператора Python по модулю (%
), ознакомьтесь с учебным пособием «Python Modulo на практике: как использовать оператор %».
Затем у вас есть оператор по модулю и кортеж значений или выражений. Оператор будет интерполировать каждое значение в этом кортеже в соответствующий спецификатор, используя их позицию.
Интерполяция одного или нескольких значений
В предыдущем разделе вы видели пример, в котором вы интерполировали несколько значений или выражений в строку с помощью оператора по модулю. Если вам нужно вставить только одно значение, вы можете пропустить кортеж или использовать кортеж из одного элемента:
>>> "Hello, %s!" % "Pythonista"
'Hello, Pythonista!'
>>> "Hello, %s!" % ("Pythonista",)
'Hello, Pythonista!'
Первый синтаксис немного чище второго. Однако для обеспечения единообразия всего кода вы можете использовать второй синтаксис.
Что же происходит, когда вам нужно интерполировать объект-кортеж? Вот пример:
>>> "Interpolating a tuple: %s" % (1, 2, 3)
Traceback (most recent call last):
File "<input>", line 1, in <module>
"Interpolating a tuple: %s" % (1, 2, 3)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: not all arguments converted during string formatting
В этом примере Python интерпретирует кортеж как три разных значения, и вы получаете ошибку, поскольку строка имеет только одно поле замены. Чтобы обойти эту проблему, вам нужно использовать кортеж из одного элемента:
>>> "Interpolating a tuple: %s" % ((1, 2, 3),)
'Interpolating a tuple: (1, 2, 3)'
Теперь интерполяция работает правильно, и в итоге вы получаете кортеж, вставленный в строку. Важно отметить, что вы должны использовать кортежи, если хотите передать несколько значений в оператор по модулю:
>>> "Hello, %s! Today is %s." % [name, day]
Traceback (most recent call last):
File "<input>", line 1, in <module>
"Hello, %s! Today is %s." % [name, day]
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
TypeError: not enough arguments for format string
>>> "The sum of %d and %d is %d." % [x, y, x + y]
Traceback (most recent call last):
File "<input>", line 1, in <module>
"The sum of %d and %d is %d." % [x, y, x + y]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
TypeError: %d format: a real number is required, not list
Если вы используете объект list
или другой итерируемый объект, Python интерпретирует его как один объект, и интерполяция завершится с ошибкой TypeError
.
Использование именованных полей замены
В предыдущем разделе вы узнали, что следует использовать кортеж для предоставления нескольких аргументов оператору по модулю для интерполяции строк. Таким образом, оператор вставляет значения кортежа в целевую строку по их позиции, но это не очень удобно для чтения.
К счастью, есть лучший способ. Вы также можете использовать словари и именованные поля замены:
>>> jane = {"name": "Jane", "job": "Python Dev"}
>>> "My name is %(name)s. I'm a %(job)s." % jane
"My name is Jane. I'm a Python Dev."
В этом примере оператор по модулю вставляет каждое значение, используя соответствующий ключ, что намного более читабельно и интуитивно понятно. Чтобы создать именованные поля замены, вам необходимо вставить имя в круглые скобки между знаком %
и спецификатором формата.
Использование различных представлений строк
Вы также можете использовать различные строковые представления объектов с помощью оператора по модулю для интерполяции строк. Вы уже узнали, что спецификатор преобразования %s
преобразует объект в строки. Для этого спецификатор использует удобное представление специального метода .__str__()
.
Чтобы использовать удобное для разработчиков строковое представление, представленное в .__repr__()
, вы можете использовать спецификатор преобразования %r
.
Чтобы проиллюстрировать, как это сделать, вы можете снова использовать класс Article
:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print("%s" % article)
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print("%r" % article)
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
Итоговое поведение такое же, как и в случае с f-строками и методом .format()
. Опять же, выбор того, какое строковое представление использовать, будет зависеть от целевой аудитории вашего кода.
Использование F-строк вместо .format()
и %
К этому моменту вы узнали о трех различных инструментах Python, которые можно использовать для интерполяции строк. Может возникнуть вопрос: какой инструмент следует использовать? Как и во многих других случаях, ответ таков: это зависит.
Если вам нужен читаемый синтаксис и хорошая производительность при интерполяции строк, а вы выполняете только быструю интерполяцию, то f-строки для вас. Если вам нужен инструмент для ленивой интерполяции строк, то вам подойдет метод .format()
.
Напротив, оператор по модулю (%
) — это старомодный инструмент, который обычно не используется в современном Python. Можно сказать, что этот инструмент почти мертв. Однако вы можете найти его в устаревшем коде Python, поэтому полезно узнать, как он работает.
В следующей таблице сравниваются три инструмента по нескольким критериям сравнения:
Feature | F-strings | .format() |
% |
---|---|---|---|
Readability | High | Medium | Low |
Supports lazy evaluation | ⛔️ | ✅ | ✅ |
Supports dictionary unpacking | ⛔️ | ✅ | ✅ |
Supports the format mini-language | ✅ | ✅ | ⛔️ |
Фа-строки — явный победитель с точки зрения читабельности. Однако они не позволяют выполнять ленивую интерполяцию. Невозможно использовать f-строку для создания повторно используемого шаблона строки, который вы сможете позже интерполировать в своем коде.
Кроме того, вы не можете использовать словарь для предоставления входных значений за один раз. Это не означает, что вы не можете интерполировать словарные ключи в f-строку:
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> f"{numbers['one']}-{numbers['two']}-{numbers['three']}"
'1-2-3'
Чтобы интерполировать ключи словаря в f-строку, вам необходимо вставить ключ в нужное поле замены. Из-за этого ваша f-строка может выглядеть загроможденной, и ее будет трудно читать и писать. В таких случаях лучше использовать метод .format()
:
>>> "{one}-{two}-{three}".format(**numbers)
'1-2-3'
>>> "{one}-{two}".format(**numbers)
'1-2'
Этот код гораздо более читабелен и быстрее пишется, чем версия с f-строкой. Дополнительным преимуществом является то, что количество ключей во входном словаре не обязательно должно совпадать с количеством полей замены в строке шаблона, что делает код более гибким и универсальным.
Наконец, и f-строки, и метод .format()
поддерживают мини-язык форматирования строк Python, который позволяет красиво форматировать интерполированные значения. В качестве краткого примера, вот как можно отформатировать константу π, используя четыре десятичных знака:
>>> import math
>>> math.pi
3.141592653589793
>>> f"{math.pi:.4f}"
'3.1416'
>>> "{pi:.4f}".format(pi=math.pi)
'3.1416'
Форматирование интерполированных значений с использованием мини-языка форматирования выходит за рамки данного руководства. Если вы хотите глубже изучить эту тему, ознакомьтесь с руководством по мини-языку форматирования Python для аккуратных строк.
Создание шаблонов с помощью класса Template
В Python есть еще один инструмент для интерполяции строк. В модуле string
вы найдете класс Template
. Как следует из названия, этот класс позволяет создавать шаблоны строк, которые можно использовать для ленивой интерполяции.
Вы обнаружите два основных различия между Template
и стандартными инструментами интерполяции строк. При использовании Template
тип интерполируемых значений не учитывается. Значения автоматически преобразуются в строки, а затем вставляются в шаблон.
Кроме того, Template
не поддерживает форматирование строк. С другой стороны, стандартные инструменты имеют то преимущество, что поддерживают мини-язык форматирования строк, который поможет вам точно настроить строки.
Примечание. Класс Template
предназначен для того, чтобы помочь вам создавать сложные строковые шаблоны, с которыми вы можете легко работать. Однако в большинстве ситуаций метод .format()
обеспечивает более полное решение.
Чтобы создать строку шаблона с помощью Template
, вам понадобится обычная строка Python со встроенными заполнителями. Эти заполнители состоят из двух частей:
- Знак доллара (
$
) - Действительный идентификатор Python
Допустимые идентификаторы — это те, которые вы можете использовать в качестве имен переменных в Python. Они сочетают в себе прописные и строчные буквы, символы подчеркивания (_
) и цифры. Идентификаторы не могут начинаться с цифр или соответствовать ключевому слову Python. Например, $name
, $age
, $Tag
, $class_
и $item_1
— все допустимые заполнители.
После того как вы создали строку с соответствующими заполнителями, вам необходимо:
- Импортируйте
Template
из модуляstring
. - Создайте экземпляр
Template
, используя строку шаблона в качестве аргумента. - Выполните замену одним из двух соответствующих методов.
Вот краткий пример того, как вы можете использовать Template
в своем коде:
>>> from string import Template
>>> template = Template("Hello, $name! Today is $day.")
>>> template.substitute(name="John", day="Friday")
'Hello, John! Today is Friday.'
В этом примере вы используете строку шаблона с двумя заполнителями: $name
и $day
в качестве аргумента Template
. После создания экземпляра класса вы можете вызвать .substitute()
для интерполяции значений. Обратите внимание, что имена аргументов, которые вы передаете в .substitute()
, должны соответствовать идентификаторам, используемым в заполнителях строки вашего шаблона.
В следующих разделах вы узнаете больше о создании строк шаблона с помощью класса Template
.
Создание строк шаблона
Чтобы создать допустимые строки шаблона, которые можно передать в класс Template
, необходимо учитывать некоторые основные правила. Вот как PEP 292 описывает эти правила:
$$
— это escape; он заменяется одним$
$identifier
называет заполнитель подстановки, соответствующий ключу сопоставления «идентификатор». По умолчанию «идентификатор» должен означать идентификатор Python, как определено в [2]. Первый неидентифицирующий символ после символа$
завершает эту спецификацию заполнителя.$ {identifier
эквивалентен$identifier
. Это требуется, когда действительные символы идентификатора следуют за заполнителем, но не являются его частью, например."$ {существительное}ификация"
. (Источник)
Для начала вы начнете с примера того, как избежать знака доллара ($
), который необходим для выражения значений валюты, например:
>>> from string import Template
>>> Template("$$$amount").substitute(amount="1,000.00")
'$1,000.00'
В этом шаблоне строки первые два знака доллара экранируют требуемый знак доллара, а последний знак доллара определяет заполнитель.
Второе правило гласит, что каждому заполнителю необходим символ $
, за которым следует действительный идентификатор Python. Вот пример:
>>> Template("$greeting, $who!").substitute(greeting="Hello", who="World")
'Hello, World!'
В этом примере вы формируете заполнители, используя допустимые идентификаторы Python: приветствие
и who
. Как гласит второе правило, первый неидентифицирующий символ завершает заполнитель, так что это касается запятой после $greeting
и восклицательного знака после $who
.
Третье правило применимо к ситуациям, когда нужно заменить слово в строке, а символы, следующие за идентификатором, допустимы для построения идентификаторов. В этой ситуации Python не будет знать, где заканчивается идентификатор.
Например, предположим, что вам нужен шаблон, позволяющий отображать сумму денег в долларах США. В этой ситуации вы можете сделать что-то вроде следующего:
>>> Template("${amount}USD").substitute(amount="100")
'100USD'
>>> Template("$amountUSD").substitute(amount="100")
Traceback (most recent call last):
...
KeyError: 'amountUSD'
Поскольку USD
— это все символы, которые можно использовать в допустимом идентификаторе Python, вам необходимо использовать стиль заполнителя $ {identifier
. В противном случае вы получите KeyError
.
Наконец, строка шаблона, которую вы передаете конструктору Template()
, сохраняется в атрибуте .template
. Это позволяет вам динамически изменять шаблон:
>>> greeting = Template("Hello, $name! Today is $day.")
>>> greeting.substitute(name="John", day="Friday")
'Hello, John! Today is Friday.'
>>> greeting.template = "Hello, $name! Welcome!"
>>> greeting.substitute(name="John")
'Hello, John! Welcome!'
Вы можете изменить атрибут .template
в любое время. Однако лучше всего создавать новые экземпляры Template
для каждой отдельной строки шаблона в вашем коде. Таким образом, вы предотвратите мелкие ошибки или даже поломку шаблонов.
Замена значений с помощью .substitute()
До этого момента вы использовали метод .substitute()
с аргументами ключевых слов для интерполяции значений в шаблонах строк. Вы также можете использовать методы со словарями:
>>> from string import Template
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> Template("$one-$two-$three").substitute(**numbers)
'1-2-3'
Опять же, когда вы используете словарь в качестве аргумента для substitute()
, вам необходимо использовать оператор распаковки словаря (**
). Этот оператор распакует пары ключ-значение в аргументы ключевых слов, которые будут вставлены в соответствующие заполнители в строке шаблона.
Обратите внимание, что имена заполнителей должны соответствовать ключам словаря. Если заполнитель не соответствует ни одному ключу или количество ключей не соответствует количеству заполнителей, вы получите сообщение об ошибке:
>>> numbers = {"one": 1, "two": 2}
>>> Template("$one-$two-$three").substitute(**numbers)
Traceback (most recent call last):
...
KeyError: 'three'
Если вы вызываете .substitute()
со словарем, ключи которого не соответствуют всем заполнителям в строке шаблона, вы получите KeyError
.
Замена значений с помощью .safe_substitute()
В Template
есть еще один метод, который можно использовать для интерполяции значений в шаблон строки. Этот метод называется .safe_substitute()
и работает аналогично .substitute()
. Однако если вы используете неполный или несовпадающий набор аргументов, метод не вызывает KeyError
:
>>> from string import Template
>>> numbers = {"one": 1, "two": 2}
>>> Template("$one-$two-$three").safe_substitute(**numbers)
'1-2-$three'
В этом фрагменте кода вы вызываете .safe_substitute()
, используя словарь, ключи которого не соответствуют всем существующим заполнителям. Вместо исключения KeyError
вы получаете строку, которая буквально показывает отсутствующий заполнитель. Это может быть полезно для выявления недостающих значений внутри представления HTML-страницы, подлежащей рендерингу.
Метод .safe_substitute()
может быть преимуществом использования Template
перед методом .format()
:
>>> "{one}-{two}-{three}".format(**numbers)
Traceback (most recent call last):
...
KeyError: 'three'
Метод .format()
не имеет безопасного способа выполнения интерполяции при использовании неполного или несовпадающего набора аргументов.
Заключение
Вы узнали, как выполнять интерполяцию строк и создавать новые строки, вставляя объекты в шаблон строки. Теперь вы знаете, что в Python есть несколько инструментов для интерполяции строк. К этим инструментам относятся f-строки, метод str.format()
и оператор по модулю (%
).
Вы также узнали о классе Template
, который также можно использовать для интерполяции строк. Этот класс входит в модуль стандартной библиотеки под названием string
.
В этом уроке вы:
- Научились использовать f-строки для интерполяции строк eager.
- Выполнена ленивая интерполяция строк с помощью
str.format()
- Использовал оператор по модулю (
%
) для интерполяции строк. - Научены, когда использовать f-строки или
str.format()
для интерполяции. - Выполнена интерполяция строк с помощью класса
string.Template
.
Теперь у вас есть необходимые навыки, чтобы начать создавать строки с использованием различных инструментов интерполяции. Какой инструмент вы используете, будет зависеть от вашего конкретного случая использования.