Руководство по новым методам форматирования строк в Python
Оглавление
- Метод Python String .format()
- Метод String .format(): Аргументы
- Метод String .format(): Простая замена полей
- Метод String .format(): Вложенные поля-заменители
- Букварь форматированной строки Python (f-String)
- Заключение
В предыдущем уроке из этой вводной серии вы впервые узнали, как можно форматировать строки с помощью Python f-строк. Более подробно об этой технике вы узнаете в конце этого урока.
Поскольку f-строки появились в языке Python сравнительно недавно, вам будет полезно познакомиться и со второй, чуть более старой техникой. Скорее всего, вы встретите ее в более старом коде Python.
В этом уроке вы узнаете о:
- Метод string
.format()
- Литерал форматированной строки, или f-строка
Вы подробно познакомитесь с этими техниками форматирования и добавите их в свой набор инструментов для форматирования строк в Python.
Примечание: Существует стандартный модуль string
, содержащий класс Template
, который также обеспечивает некоторое форматирование строк с помощью интерполяции. Родственная техника, оператор модуляции строк , обеспечивает примерно ту же функциональность. В этом уроке мы не будем рассматривать ни одну из этих техник, но вам стоит почитать об операторе string modulo operator, если вам придется работать с кодом, написанным на Python 2.
Вы можете заметить, что в Python существует множество различных способов форматирования строк, что противоречит одной из собственных мантр Python:
Должен быть один и, желательно, только один - очевидный способ сделать это. -Тим Питерс, The Zen of Python
За годы существования и развития Python различные методы форматирования строк развивались исторически. Старые методы сохраняются для обеспечения обратной совместимости, а некоторые даже имеют специфическое применение.
Если вы только начинаете изучать Python и ищете единственный способ форматирования строк, то остановитесь на f-stringsPython. Если вы столкнулись со странным кодом формата строк и хотите узнать больше, или вам нужно работать со старыми версиями Python, тогда вам стоит узнать и о других методах.
Метод Python String .format()
Метод .format()
был представлен в версии 2.6. Он во многом похож на оператор модуляции строк, но .format()
значительно превосходит его по универсальности. Общая форма вызова Python .format()
показана ниже:
<template>.format(<positional_argument(s)>, <keyword_argument(s)>)
Обратите внимание, что это метод, а не оператор. Вы вызываете метод на <template>
, который представляет собой строку, содержащую поля-заменители . В <positional_arguments>
и <keyword_arguments>
к методу указываются значения, которые вставляются в <template>
вместо полей-заменителей. Полученная отформатированная строка является возвращаемым значением метода.
В строке <template>
поля замены заключены в фигурные скобки ({}
). Все, что не заключено в фигурные скобки, является буквальным текстом, который копируется непосредственно из шаблона в вывод. Если вам необходимо включить в строку шаблона буквальный символ фигурных скобок, например {
или }
, то вы можете избежать этого символа, удвоив его:
>>> '{{ {0} }}'.format('foo')
'{ foo }'
Теперь фигурные скобки включены в вывод.
Метод String .format()
: Аргументы
Начнем с небольшого примера, чтобы познакомить вас с ним, прежде чем вы погрузитесь в более подробную информацию о том, как использовать этот метод в Python для форматирования строк. Если использовать старую технику форматирования с помощью оператора модуляции строки , то код будет немного трудночитаемым:
>>> print('%d %s cost $%.2f' % (6, 'bananas', 1.74))
6 bananas cost $1.74
В приведенном выше примере для форматирования строки использовался оператор модуляции строки. Для лучшей читабельности можно использовать метод Python .format()
для получения того же результата:
>>> print('{0} {1} cost ${2}'.format(6, 'bananas', 1.74))
6 bananas cost $1.74
В данном примере <template>
- это строка '{0} {1} cost ${2}'
. Поля замены {0}
, {1}
и {2}
содержат числа, соответствующие нулевым позиционным аргументам 6
, 'bananas'
и 1.74
. Каждый позиционный аргумент вставляется в шаблон на место соответствующего поля замены:
Использование метода String .format() в Python для форматирования строки с позиционными аргументами
В следующем примере вместо позиционных параметров используются аргументы ключевого слова, что приводит к тому же результату:
>>> print('{quantity} {item} cost ${price}'.format(
... quantity=6,
... item='bananas',
... price=1.74))
6 bananas cost $1.74
В этом случае полями замены будут {quantity}
, {item}
и {price}
. Эти поля задают ключевые слова, соответствующие аргументам ключевых слов quantity=6
, item='bananas'
и price=1.74
. Значение каждого ключевого слова вставляется в шаблон на место соответствующего поля-заменителя:
Использование метода String .format() в Python для форматирования строки с аргументами в виде ключевых слов
Более подробно о позиционных и ключевых аргументах вы узнаете в следующем уроке из этой вводной серии, где рассматриваются функции и передача аргументов. Пока же в двух последующих разделах мы покажем вам, как они используются в методе Python .format()
.
Позиционные аргументы
Позиционные аргументы вставляются в шаблон вместо пронумерованных полей замены. Как и при индексации списка, нумерация полей замены основана на нулях. Первый позиционный аргумент нумеруется 0
, второй - 1
и так далее:
>>> '{0}/{1}/{2}'.format('foo', 'bar', 'baz')
'foo/bar/baz'
Обратите внимание, что поля замены не обязательно должны располагаться в шаблоне в числовом порядке. Их можно указывать в любом порядке, и они могут появляться несколько раз:
>>> '{2}.{1}.{0}/{0}{0}.{1}{1}.{2}{2}'.format('foo', 'bar', 'baz')
'baz.bar.foo/foofoo.barbar.bazbaz'
При указании номера поля замены, выходящего за пределы диапазона, вы получите ошибку. В следующем примере позиционные аргументы пронумерованы 0
, 1
и 2
, но в шаблоне указано {3}
:
>>> '{3}'.format('foo', 'bar', 'baz')
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
'{3}'.format('foo', 'bar', 'baz')
IndexError: tuple index out of range
При этом возникает IndexError
исключение.
Начиная с Python 3.1, вы можете не указывать номера в полях замены, в этом случае интерпретатор будет считать, что они расположены в последовательном порядке. Это называется автоматической нумерацией полей:
>>> '{}/{}/{}'.format('foo', 'bar', 'baz')
'foo/bar/baz'
Когда вы задаете автоматическую нумерацию полей, вы должны предоставить по крайней мере столько аргументов, сколько имеется заменяемых полей:
>>> '{}{}{}{}'.format('foo','bar','baz')
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
'{}{}{}{}'.format('foo','bar','baz')
IndexError: tuple index out of range
В данном случае в шаблоне четыре поля замены, но только три аргумента, поэтому возникает исключение IndexError
. С другой стороны, нет ничего страшного в том, что аргументов больше, чем полей замены. Лишние аргументы просто не используются:
>>> '{}{}'.format('foo', 'bar', 'baz')
'foobar'
Здесь аргумент 'baz'
игнорируется.
Обратите внимание, что нельзя смешивать эти две техники:
>>> '{1}{}{0}'.format('foo','bar','baz')
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
'{1}{}{0}'.format('foo','bar','baz')
ValueError: cannot switch from manual field specification to automatic field
numbering
Когда вы используете Python для форматирования строк с позиционными аргументами, вы должны выбрать автоматическую или явную нумерацию полей замены.
Ключевые слова-аргументы
Ключевые слова-аргументы вставляются в строку шаблона вместо полей замены ключевых слов с тем же именем :
>>> '{x}/{y}/{z}'.format(x='foo', y='bar', z='baz')
'foo/bar/baz'
В этом примере значения аргументов ключевых слов x
, y
и z
занимают место полей замены {x}
, {y}
и {z}
, соответственно.
Если вы ссылаетесь на аргумент ключевого слова, который отсутствует, то вы увидите ошибку:
>>> '{x}/{y}/{w}'.format(x='foo', y='bar', z='baz')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'w'
Здесь вы указываете поле замены {w}
, но нет соответствующего аргумента ключевого слова w
. Python вызывает исключение KeyError
.
Хотя вы должны указывать позиционные аргументы в последовательном порядке, но вы можете указывать аргументы ключевых слов в любом произвольном порядке:
>>> '{0}/{1}/{2}'.format('foo', 'bar', 'baz')
'foo/bar/baz'
>>> '{0}/{1}/{2}'.format('bar', 'baz', 'foo')
'bar/baz/foo'
>>> '{x}/{y}/{z}'.format(x='foo', y='bar', z='baz')
'foo/bar/baz'
>>> '{x}/{y}/{z}'.format(y='bar', z='baz', x='foo')
'foo/bar/baz'
В одном вызове Python .format()
можно указать как позиционные, так и ключевые аргументы. Только учтите, что в этом случае все позиционные аргументы должны появляться перед любым из аргументов ключевого слова:
>>> '{0}{x}{1}'.format('foo', 'bar', x='baz')
'foobazbar'
>>> '{0}{x}{1}'.format('foo', x='baz', 'bar')
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
На самом деле требование, чтобы все позиционные аргументы появлялись перед любыми аргументами ключевых слов, относится не только к методам формата Python. Это требование справедливо для любого вызова функции или метода. Подробнее об этом вы узнаете в следующем уроке из этой серии, где рассматриваются функции и вызовы функций.
Во всех примерах, показанных до сих пор, значения, которые вы передавали методу Python .format()
, были буквальными значениями, но вы можете указать переменные также:
>>> x = 'foo'
>>> y = 'bar'
>>> z = 'baz'
>>> '{0}/{1}/{s}'.format(x, y, s=z)
'foo/bar/baz'
В этом случае вы передаете переменные x
и y
как значения позиционных параметров, а z
как значение параметра ключевого слова.
Метод String .format()
: Простая замена полей
Как вы видели, при вызове метода Python .format()
строка <template>
содержит поля-заменители. Они указывают, куда в шаблоне вставить аргументы метода. Поле замены состоит из трех компонентов:
{[<name>][!<conversion>][:<format_spec>]}
Эти компоненты интерпретируются следующим образом:
Component | Meaning |
---|---|
<name> |
Указывает источник форматируемого значения |
<conversion> |
Указывает, какую стандартную функцию Python следует использовать для выполнения преобразования |
<format_spec> |
Указывает более подробную информацию о том, как должно быть преобразовано значение |
Каждый компонент является необязательным и может быть опущен. Давайте рассмотрим каждый компонент более подробно.
Компонент <name>
Компонент <name>
является первой частью поля замены:
{
[<name>]
[!<conversion>][:<format_spec>]}
<name>
указывает, какой аргумент из списка аргументов будет вставлен в строку формата Python в указанном месте. Это либо число для позиционного аргумента, либо ключевое слово для аргумента с ключевым словом. В следующем примере <name>
компонентами полей замены являются 0
, 1
и baz
, соответственно:
>>> x, y, z = 1, 2, 3
>>> '{0}, {1}, {baz}'.format(x, y, baz=z)
'1, 2, 3'
Если аргумент представляет собой список, то для доступа к элементам списка можно использовать индексы с помощью <name>
:
>>> a = ['foo', 'bar', 'baz']
>>> '{0[0]}, {0[2]}'.format(a)
'foo, baz'
>>> '{my_list[0]}, {my_list[2]}'.format(my_list=a)
'foo, baz'
Аналогично, вы можете использовать ссылку на ключ с помощью <name>
, если соответствующий аргумент является словарем:
>>> d = {'key1': 'foo', 'key2': 'bar'}
>>> d['key1']
'foo'
>>> '{0[key1]}'.format(d)
'foo'
>>> d['key2']
'bar'
>>> '{my_dict[key2]}'.format(my_dict=d)
'bar'
Вы также можете ссылаться на атрибуты объекта внутри поля замены. В предыдущем уроке этой серии вы узнали, что практически каждый элемент данных в Python является объектом. Объекты могут иметь атрибуты, доступ к которым осуществляется с помощью точечной нотации:
obj.attr
Здесь obj
- это объект с атрибутом attr
. Для доступа к атрибуту объекта используется точечная нотация. Рассмотрим пример. Комплексные числа в Python имеют атрибуты .real
и .imag
, которые представляют действительную и мнимую части числа. Вы можете получить к ним доступ, используя точечную нотацию:
>>> z = 3+5j
>>> type(z)
<class 'complex'>
>>> z.real
3.0
>>> z.imag
5.0
В этой серии уроков, посвященных объектно-ориентированному программированию, вы узнаете гораздо больше об атрибутах объектов, подобных этим.
Актуальность атрибутов объекта в данном контексте заключается в том, что вы можете указать их в поле замены Python .format()
:
>>> z
(3+5j)
>>> 'real = {0.real}, imag = {0.imag}'.format(z)
'real = 3.0, imag = 5.0'
Как видите, в Python относительно просто форматировать компоненты сложных объектов с помощью метода .format()
.
Компонент <conversion>
Компонент <conversion>
является средней частью поля замены:
{[<name>]
[!<conversion>]
[:<format_spec>]}
Python может форматировать объект как строку с помощью трех различных встроенных функций:
str()
repr()
ascii()
По умолчанию метод Python .format()
использует str()
, но в некоторых случаях вам может понадобиться заставить .format()
использовать один из двух других. Это можно сделать с помощью компонента <conversion>
в поле замены. Возможные значения для <conversion>
приведены в таблице ниже:
Значение | Смысл |
---|---|
!s |
Преобразование с помощью функции str() |
!r |
Преобразование с помощью функции repr() |
!a |
Преобразование с помощью функции ascii() |
Следующие примеры заставляют Python выполнять преобразование строк с помощью str()
, repr()
и ascii()
, соответственно:
>>> '{0!s}'.format(42)
'42'
>>> '{0!r}'.format(42)
'42'
>>> '{0!a}'.format(42)
'42'
Во многих случаях результат будет одинаковым независимо от того, какую функцию преобразования вы используете, как видно из примера выше. Учитывая это, компонент <conversion>
понадобится вам нечасто, поэтому мы не будем тратить на него много времени. Однако бывают ситуации, когда он имеет значение, поэтому полезно знать, что у вас есть возможность принудительно использовать определенную функцию преобразования, если вам это необходимо.
Компонент <format_spec>
Компонент <format_spec>
является последней частью поля замены:
{[<name>][!<conversion>]
[:<format_spec>]
}
<format_spec>
представляет собой внутреннюю часть функциональности метода Python .format()
. Он содержит информацию, которая позволяет контролировать форматирование значений перед вставкой в строку шаблона. В общем виде это выглядит так:
:
[[<fill>]<align>][<sign>][#][0][<width>][<group>][.<prec>][<type>]
Десять подкомпонентов <format_spec>
задаются в указанном порядке. Они управляют форматированием, как описано в таблице ниже:
Субкомпонент | Эффект |
---|---|
: |
Отделяет <format_spec> от остальной части поля замены |
<fill> |
Указывает, как размещать значения, которые не занимают всю ширину поля. |
<align> |
Указывает, как выравнивать значения, которые не занимают всю ширину поля |
<sign> |
Контролирует, будет ли включен ведущий знак для числовых значений |
# |
Выбор альтернативной формы вывода для некоторых типов презентаций |
0 |
Заставляет значения заполняться слева нулями вместо символов пробела ASCII |
<width> |
Указывает минимальную ширину вывода |
<group> |
Specifies a grouping character for numeric output |
.<prec> |
Указывает количество цифр после десятичной точки для типов представления с плавающей точкой и максимальную ширину вывода для типов представления со строками |
<type> |
Указывает тип представления, который является типом преобразования, выполняемого для соответствующего аргумента |
Эти функции аналогичны компонентам, которые вы найдете в спецификаторе преобразования строк оператора modulo , но с несколько большими возможностями. Более подробно их возможности будут описаны в следующих разделах.
Подкомпонент <type>
Начнем с <type>
, которая является заключительной частью <format_spec>
. Подкомпонент <type>
задает тип представления, то есть тип преобразования, которое выполняется над соответствующим значением для получения выходного результата. Возможные значения показаны ниже:
Значение | Тип представления |
---|---|
b |
Двоичное целое число |
c |
Одиночный символ |
d |
Десятичное целое число |
e or E |
Экспоненциальный |
f or F |
Плавающая точка |
g or G |
Плавающая точка или экспоненциальная |
o |
Восьмеричное целое число |
s |
Строка |
x or X |
Шестнадцатеричное целое число |
% |
Процент |
Эти типы похожи на типы преобразования, используемые с оператором модуляции строк, и во многих случаях они работают одинаково. Следующие примеры демонстрируют это сходство:
>>> '%d' % 42
'42'
>>> '{:d}'.format(42)
'42'
>>> '%f' % 2.1
'2.100000'
>>> '{:f}'.format(2.1)
'2.100000'
>>> '%s' % 'foobar'
'foobar'
>>> '{:s}'.format('foobar')
'foobar'
>>> '%x' % 31
'1f'
>>> '{:x}'.format(31)
'1f'
Однако между некоторыми типами представления Python .format()
и типами преобразования оператора модуляции строк есть небольшие различия:
Тип | Метод .format() |
Строковый оператор модуло |
---|---|---|
b | Обозначает преобразование двоичных целых чисел | Не поддерживается |
i, u | Не поддерживается | Обозначает преобразование целых чисел |
c | Обозначает преобразование символов, и соответствующее значение должно быть целым числом | Обозначает преобразование символов, но соответствующее значение может быть как целым числом, так и односимвольной строкой |
g, G | Выбирает между плавающей точкой и экспоненциальным выводом, но правила, управляющие выбором, немного сложнее | Выбирает между выводом с плавающей точкой и экспонентой, в зависимости от величины экспоненты и значения, указанного для <prec> . |
r, a | Не поддерживается (хотя функциональность обеспечивается компонентами преобразования !r и !a в поле замены). |
Обозначает преобразование с помощью repr() или ascii() , соответственно |
% | Преобразует числовой аргумент в проценты | Вставляет в вывод литеральный символ '%' |
Далее вы увидите несколько примеров, иллюстрирующих эти различия, а также некоторые дополнительные возможности типов представления методов Python .format()
. Первый тип представления, который вы увидите, - b
, обозначающий двоичное целочисленное преобразование:
>>> '{:b}'.format(257)
'100000001'
Оператор modulo вообще не поддерживает двоичный тип преобразования:
>>> '%b' % 257
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: unsupported format character 'b' (0x62) at index 1
Однако оператор modulo позволяет преобразовывать десятичные целые числа с любым из типов d
, i
и u
. Только тип представления d
указывает на десятичное преобразование целых чисел с помощью метода Python .format()
. Типы представления i
и u
не поддерживаются и не являются необходимыми.
Далее следует преобразование одного символа. Оператор modulo позволяет использовать либо целое, либо односимвольное значение с типом преобразования c
:
>>> '%c' % 35
'#'
>>> '%c' % '#'
'#'
С другой стороны, метод Python .format()
требует, чтобы значение, соответствующее типу представления c
, было целым числом:
>>> '{:c}'.format(35)
'#'
>>> '{:c}'.format('#')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'c' for object of type 'str'
При попытке передать значение другого типа вы получите ошибку ValueError
.
Как для оператора модуляции строки, так и для метода Python .format()
, тип преобразования g
выбирает либо плавающую точку, либо экспоненту, в зависимости от величины экспоненты и значения, указанного для <prec>
:
>>> '{:g}'.format(3.14159)
'3.14159'
>>> '{:g}'.format(-123456789.8765)
'-1.23457e+08'
Точные правила , регулирующие выбор, несколько сложнее с .format()
, чем с оператором modulo. В целом, вы можете быть уверены, что выбор будет иметь смысл.
G
идентичен g
, за исключением случаев, когда вывод экспоненциальный, в этом случае 'E'
будет в верхнем регистре:
>>> '{:G}'.format(-123456789.8765)
'-1.23457E+08'
Результат тот же, что и в предыдущем примере, но на этот раз с прописной буквы 'E'
.
Примечание: Есть еще несколько ситуаций, в которых вы увидите разницу между типами презентаций g
и G
.
При некоторых обстоятельствах операция с плавающей точкой может привести к значению, которое по сути бесконечно. Строковое представление такого числа в Python - 'inf'
. Также может случиться, что в результате операции с плавающей точкой получается значение, которое нельзя представить в виде числа. В Python это обозначается строкой 'NaN'
, которая расшифровывается как Not a Number.
Когда вы передаете эти значения методу Python .format()
, тип представления g
выводит строчные буквы, а G
выводит прописные:
>>> x = 1e300 * 1e300
>>> x
inf
>>> '{:g}'.format(x)
'inf'
>>> '{:g}'.format(x * 0)
'nan'
>>> '{:G}'.format(x)
'INF'
>>> '{:G}'.format(x * 0)
'NAN'
Вы увидите аналогичное поведение с типами презентаций f
и F
:
>>> '{:f}'.format(x)
'inf'
>>> '{:F}'.format(x)
'INF'
>>> '{:f}'.format(x * 0)
'nan'
>>> '{:F}'.format(x * 0)
'NAN'
Более подробную информацию о представлении с плавающей точкой, inf
и NaN
можно найти в Википедии на странице IEEE 754-1985.
Оператор modulo поддерживает типы преобразования r
и a
для принудительного преобразования по repr()
и ascii()
, соответственно. Метод Python .format()
не поддерживает типы представления r
и a
, но вы можете сделать то же самое с помощью компонентов преобразования !r
и !a
в поле замены.
Наконец, вы можете использовать тип преобразования %
с оператором modulo, чтобы вставить в вывод литеральный символ '%'
:
>>> '%f%%' % 65.0
'65.000000%'
Для вставки литерального символа '%'
в вывод метода Python .format()
не нужно ничего особенного, поэтому тип представления %
служит другой удобной цели для вывода процентов. Он умножает указанное значение на 100 и добавляет знак процента:
>>> '{:%}'.format(0.65)
'65.000000%'
<<<Оставшиеся части
указывают, <format_spec>
как форматируется выбранный тип представления, примерно так же, как спецификаторы ширины и точности и флаги преобразования оператора строковой модуляции . Более подробно они описаны в следующих разделах.
Состав <fill>
и <align>
Подкомпоненты
<fill>
и <align>
управляют тем, как форматированный вывод заполняется и позиционируется в пределах заданной ширины поля. Эти подкомпоненты имеют смысл только тогда, когда значение форматированного поля не занимает всю ширину поля, что может произойти только в том случае, если минимальная ширина поля задана с помощью <width>
. Если <width>
не указан, то <fill>
и <align>
фактически игнорируются. О <width>
вы узнаете позже в этом учебнике.
Вот возможные значения для подкомпонента <align>
:
<
>
^
=
Значение с использованием знака "меньше, чем" (<
) указывает на то, что вывод выравнивается по левому краю:
>>> '{0:<8s}'.format('foo')
'foo '
>>> '{0:<8d}'.format(123)
'123 '
Это поведение по умолчанию для строковых значений.
Значение с использованием знака "больше чем" (>
) указывает на то, что вывод должен быть выровнен по правому краю:
>>> '{0:>8s}'.format('foo')
' foo'
>>> '{0:>8d}'.format(123)
' 123'
Это поведение по умолчанию для числовых значений.
Значение с использованием каретки (^
) указывает на то, что вывод должен быть центрирован в поле вывода:
>>> '{0:^8s}'.format('foo')
' foo '
>>> '{0:^8d}'.format(123)
' 123 '
Наконец, вы также можете указать значение с помощью знака равенства (=
) для подкомпонента <align>
. Это имеет значение только для числовых значений и только в том случае, если знак включен в вывод.
Когда числовой вывод включает знак, он обычно располагается непосредственно слева от первой цифры числа, как показано выше. Если для <align>
установлен знак равенства (=
), то знак появляется у левого края поля вывода, а между знаком и числом помещается подложка:
>>> '{0:+8d}'.format(123)
' +123'
>>> '{0:=+8d}'.format(123)
'+ 123'
>>> '{0:+8d}'.format(-123)
' -123'
>>> '{0:=+8d}'.format(-123)
'- 123'
Вы подробно рассмотрите компонент <sign>
в следующем разделе.
<fill>
указывает, как заполнить дополнительное пространство, если отформатированное значение не полностью заполняет ширину вывода. Это может быть любой символ, кроме фигурных скобок ({}
). (Если вы действительно считаете необходимым заполнить поле фигурными скобками, то вам придется найти другой способ!)
Ниже приведены примеры использования <fill>
:
>>> '{0:->8s}'.format('foo')
'-----foo'
>>> '{0:#<8d}'.format(123)
'123#####'
>>> '{0:*^8s}'.format('foo')
'**foo***'
Если вы указываете значение для <fill>
, то вы должны также указать значение для <align>
.
Подкомпонент <sign>
С помощью компонента <sign>
можно контролировать появление знака в числовом выводе. Например, в следующем примере знак плюс (+
), указанный в <format_spec>
, указывает на то, что значение всегда должно отображаться с ведущим знаком:
>>> '{0:+6d}'.format(123)
' +123'
>>> '{0:+6d}'.format(-123)
' -123'
Здесь используется знак плюс (+
), поэтому знак всегда будет включен как для положительных, так и для отрицательных значений. Если вы используете знак минус (-
), то только отрицательные числовые значения будут содержать ведущий знак, а положительные - нет:
>>> '{0:-6d}'.format(123)
' 123'
>>> '{0:-6d}'.format(-123)
' -123'
Когда вы используете одиночный пробел (' '
), это означает, что для отрицательных значений используется знак, а для положительных - символ ASCII пробела:
>>> '{0:*> 6d}'.format(123)
'** 123'
>>> '{0:*>6d}'.format(123)
'***123'
>>> '{0:*> 6d}'.format(-123)
'**-123'
Поскольку символ пробела является символом заполнения по умолчанию, вы заметите его эффект только в том случае, если будет указан альтернативный символ <fill>
.
Наконец, вспомните, что когда вы указываете знак равенства (=
) для <align>
и включаете спецификатор <sign>
, прокладка идет между знаком и значением, а не слева от знака.
Подкомпонент #
Когда вы указываете хэш-символ (#
) в <format_spec>
, Python будет выбирать альтернативную форму вывода для определенных типов представления. Это аналогично флагу преобразования #
для оператора модуляции строки. Для двоичного, восьмеричного и шестнадцатеричного типов представления символ хэша (#
) вызывает включение явного индикатора основания слева от значения:
>>> '{0:b}, {0:#b}'.format(16)
'10000, 0b10000'
>>> '{0:o}, {0:#o}'.format(16)
'20, 0o20'
>>> '{0:x}, {0:#x}'.format(16)
'10, 0x10'
Как видите, базовый индикатор может быть 0b
, 0o
или 0x
.
Для типов представления с плавающей точкой или экспоненциального типа символ хеша заставляет вывод содержать десятичную точку, даже если вывод состоит из целого числа:
>>> '{0:.0f}, {0:#.0f}'.format(123)
'123, 123.'
>>> '{0:.0e}, {0:#.0e}'.format(123)
'1e+02, 1.e+02'
Для любого типа представления, кроме показанных выше, символ хэша (#
) не имеет значения.
Подкомпонент 0
Если вывод меньше указанной ширины поля и вы указали цифру ноль (0
) в <format_spec>
, то значения будут заполнены слева нулями вместо символов ASCII пробела:
>>> '{0:05d}'.format(123)
'00123'
>>> '{0:08.1f}'.format(12.3)
'000012.3'
Обычно вы используете это для числовых значений, как показано выше. Однако он работает и для строковых значений:
>>> '{0:>06s}'.format('foo')
'000foo'
Если вы указали и <fill>
, и <align>
, то <fill>
отменяет действие 0
:
>>> '{0:*>05d}'.format(123)
'**123'
<fill>
и 0
по сути управляют одним и тем же, поэтому нет необходимости указывать оба варианта. На самом деле, 0
действительно лишний, и, вероятно, был включен для удобства разработчиков, которые знакомы с аналогичным флагом преобразования 0
в операторе модуляции строк.
Подкомпонент <width>
<width>
задает минимальную ширину поля вывода:
>>> '{0:8s}'.format('foo')
'foo '
>>> '{0:8d}'.format(123)
' 123'
Обратите внимание, что это минимальная ширина поля. Предположим, вы укажете значение, которое больше минимального:
>>> '{0:2s}'.format('foobar')
'foobar'
В этом случае <width>
фактически игнорируется.
Подкомпонент <group>
<group>
позволяет включить в числовой вывод символ-разделитель группировки. Для десятичного представления и представления с плавающей точкой <group>
может быть указан как символ запятой (,
) или символ подчеркивания (_
). Этот символ разделяет каждую группу из трех цифр в выводе:
>>> '{0:,d}'.format(1234567)
'1,234,567'
>>> '{0:_d}'.format(1234567)
'1_234_567'
>>> '{0:,.2f}'.format(1234567.89)
'1,234,567.89'
>>> '{0:_.2f}'.format(1234567.89)
'1_234_567.89'
Значение <group>
с использованием символа подчеркивания (_
) также может быть указано в двоичном, восьмеричном и шестнадцатеричном типах представления. В этом случае каждая группа из четырех цифр разделяется символом подчеркивания в выводе:
>>> '{0:_b}'.format(0b111010100001)
'1110_1010_0001'
>>> '{0:#_b}'.format(0b111010100001)
'0b1110_1010_0001'
>>> '{0:_x}'.format(0xae123fcc8ab2)
'ae12_3fcc_8ab2'
>>> '{0:#_x}'.format(0xae123fcc8ab2)
'0xae12_3fcc_8ab2'
Если вы попытаетесь указать <group>
с любым типом представления, кроме перечисленных выше, то ваш код вызовет исключение.
Подкомпонент .<prec>
.<prec>
задает количество цифр после десятичной точки для типов представления с плавающей точкой:
>>> '{0:8.2f}'.format(1234.5678)
' 1234.57'
>>> '{0:8.4f}'.format(1.23)
' 1.2300'
>>> '{0:8.2e}'.format(1234.5678)
'1.23e+03'
>>> '{0:8.4e}'.format(1.23)
'1.2300e+00'
Для строковых типов .<prec>
задает максимальную ширину преобразованного вывода:
>>> '{:.4s}'.format('foobar')
'foob'
Если вывод будет длиннее указанного значения, то он будет усечен.
Метод String .format()
: Вложенные поля-заменители
Напомним, что звездочкой можно указать либо <width>
, либо <prec>
с помощью строкового оператора modulo:
>>> w = 10
>>> p = 2
>>> '%*.*f' % (w, p, 123.456) # Width is 10, precision is 2
' 123.46'
Затем соответствующие значения берутся из списка аргументов. Это позволяет динамически оценивать <width>
и <prec>
во время выполнения, как показано в примере выше. Метод .format()
в Python предоставляет аналогичные возможности, используя вложенные поля замены.
Внутри поля замены можно указать вложенный набор фигурных скобок ({}
), который содержит имя или число, относящееся к одному из позиционных или ключевых аргументов метода. Эта часть поля замены будет оценена во время выполнения и заменена соответствующим аргументом. Того же эффекта, что и в приведенном выше примере с оператором модуляции строки, можно добиться с помощью вложенных полей замены:
>>> w = 10
>>> p = 2
>>> '{2:{0}.{1}f}'.format(w, p, 123.456)
' 123.46'
Здесь <name>
компонентом поля замены является 2
, что указывает на третий позиционный параметр, значение которого 123.456
. Это и есть форматируемое значение. Вложенные поля замены {0}
и {1}
соответствуют первому и второму позиционным параметрам, w
и p
. Они занимают места <width>
и <prec>
в <format_spec>
и позволяют оценивать ширину и точность поля во время выполнения.
Вы также можете использовать аргументы ключевых слов с вложенными полями замены. Этот пример функционально эквивалентен предыдущему:
>>> w = 10
>>> p = 2
>>> '{val:{wid}.{pr}f}'.format(wid=w, pr=p, val=123.456)
' 123.46'
В любом случае, значения w
и p
оцениваются во время выполнения и используются для модификации <format_spec>
. Результат фактически аналогичен следующему:
>>> '{0:10.2f}'.format(123.456)
' 123.46'
Оператор модуляции строк позволяет только <width>
и <prec>
оценивать таким образом во время выполнения. В отличие от этого, в методе Python .format()
вы можете указать любую часть <format_spec>
с помощью вложенных полей замены.
В следующем примере тип представления <type>
задается вложенным полем замены и определяется динамически:
>>> bin(10), oct(10), hex(10)
('0b1010', '0o12', '0xa')
>>> for t in ('b', 'o', 'x'):
... print('{0:#{type}}'.format(10, type=t))
...
0b1010
0o12
0xa
Здесь группирующий символ <group>
является вложенным:
>>> '{0:{grp}d}'.format(123456789, grp='_')
'123_456_789'
>>> '{0:{grp}d}'.format(123456789, grp=',')
'123,456,789'
Фух! Это было приключение. Спецификация строки шаблона - это практически отдельный язык!
Как видите, форматирование строк может быть очень тонко настроено при использовании метода Python .format()
. Далее вы увидите еще одну технику форматирования строк и вывода, которая обладает всеми преимуществами .format()
, но имеет более прямой синтаксис.
Букварь форматированной строки Python (f-String)
В версии 3.6 появился новый синтаксис форматирования строк Python, называемый форматированным строковым литералом. Их также неофициально называют f-строками, термин, который был первоначально введен в PEP 498, где они были впервые предложены.
f-String Syntax
Строка f выглядит очень похоже на типичную строку Python, за исключением того, что к ней добавляется символ f
:
>>> f'foo bar baz'
'foo bar baz'
Вы также можете использовать заглавные буквы F
:
>>> s = F'qux quux'
>>> s
'qux quux'
Эффект точно такой же. Как и для любого другого типа строк, для определения f-строки можно использовать одинарные, двойные или тройные кавычки:
>>> f'foo'
'foo'
>>> f"bar"
'bar'
>>> f'''baz'''
'baz'
Магия f-строк заключается в том, что вы можете встраивать выражения Python непосредственно в них. Любая часть f-строки, заключенная в фигурные скобки ({}
), рассматривается как выражение. Выражение оценивается и преобразуется в строковое представление, а результат интерполируется в исходную строку в этом месте:
>>> s = 'bar'
>>> print(f'foo.{s}.baz')
foo.bar.baz
Интерпретатор обрабатывает оставшуюся часть f-строки - все, что не находится внутри фигурных скобок, - так же, как и обычную строку. Например, экранирующие последовательности обрабатываются так, как и ожидалось:
>>> s = 'bar'
>>> print(f'foo\n{s}\nbaz')
foo
bar
baz
Вот пример, приведенный ранее, с использованием f-строки:
>>> quantity = 6
>>> item = 'bananas'
>>> price = 1.74
>>> print(f'{quantity} {item} cost ${price}')
6 bananas cost $1.74
Это эквивалентно следующему:
>>> quantity = 6
>>> item = 'bananas'
>>> price = 1.74
>>> print('{0} {1} cost ${2}'.format(quantity, item, price))
6 bananas cost $1.74
Выражения, вложенные в f-строки, могут быть почти произвольно сложными. Приведенные ниже примеры демонстрируют некоторые из возможностей:
-
Переменные:
>>> quantity, item, price = 6, 'bananas', 1.74 >>> f'{quantity} {item} cost ${price}' '6 bananas cost $1.74'
-
Арифметические выражения:
>>> quantity, item, price = 6, 'bananas', 1.74 >>> print(f'Price per item is ${price/quantity}') Price per item is $0.29 >>> x = 6 >>> print(f'{x} cubed is {x**3}') 6 cubed is 216
-
Объекты составных типов:
>>> a = ['foo', 'bar', 'baz'] >>> d = {'foo': 1, 'bar': 2} >>> print(f'a = {a} | d = {d}') a = ['foo', 'bar', 'baz'] | d = {'foo': 1, 'bar': 2}
-
Индексирование, нарезка и ключевые ссылки:
>>> a = ['foo', 'bar', 'baz'] >>> d = {'foo': 1, 'bar': 2} >>> print(f'First item in list a = {a[0]}') First item in list a = foo >>> print(f'Last two items in list a = {a[-2:]}') Last two items in list a = ['bar', 'baz'] >>> print(f'List a reversed = {a[::-1]}') List a reversed = ['baz', 'bar', 'foo'] >>> print(f"Dict value for key 'bar' is {d['bar']}") Dict value for key 'bar' is 2
-
Вызовы функций и методов:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux'] >>> print(f'List a has {len(a)} items') List a has 5 items >>> s = 'foobar' >>> f'--- {s.upper()} ---' '--- FOOBAR ---' >>> d = {'foo': 1, 'bar': 2} >>> print(f"Dict value for key 'bar' is {d.get('bar')}") Dict value for key 'bar' is 2
-
Условные выражения:
>>> x = 3 >>> y = 7 >>> print(f'The larger of {x} and {y} is {x if x > y else y}') The larger of 3 and 7 is 7 >>> age = 13 >>> f'I am {"a minor" if age < 18 else "an adult"}.' 'I am a minor.'
-
Атрибуты объекта:
>>> z = 3+5j >>> z (3+5j) >>> print(f'real = {z.real}, imag = {z.imag}') real = 3.0, imag = 5.0
Чтобы включить литеральную фигурную скобку в f-строку, уберите ее, удвоив, так же, как это делается в строке шаблона для метода Python .format()
:
>>> z = 'foobar'
>>> f'{{ {z[::-1]} }}'
'{ raboof }'
Вы можете снабдить f-строку префиксом 'r'
или 'R'
, чтобы указать, что она является сырой f-строкой. В этом случае последовательности обратных косых черточек остаются нетронутыми, как и в случае с обычной строкой:
>>> z = 'bar'
>>> print(f'foo\n{z}\nbaz')
foo
bar
baz
>>> print(rf'foo\n{z}\nbaz')
foo\nbar\nbaz
>>> print(fr'foo\n{z}\nbaz')
foo\nbar\nbaz
Обратите внимание, что вы можете сначала указать 'r'
, а затем 'f'
, или наоборот.
Ограничения выражения f-String
Существует несколько незначительных ограничений на выражение f-строки. Они не слишком ограничивают, но вы должны знать, что это такое. Во-первых, выражение f-строки не может быть пустым:
>>> f'foo{}bar'
File "<stdin>", line 1
SyntaxError: f-string: empty expression not allowed
Не очевидно, зачем вам это нужно. Но если вы чувствуете, что вынуждены попробовать, то знайте, что это не сработает.
Дополнительно, выражение f-строки не может содержать символ обратной косой черты (\
) . Кроме всего прочего, это означает, что в выражении f-строки нельзя использовать последовательность символов обратной косой черты:
>>> print(f'foo{\n}bar')
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash
>>> print(f'foo{\'}bar')
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash
Вы можете обойти это ограничение, создав временную переменную, содержащую последовательность символов, которую вы хотите вставить:
>>> nl = '\n'
>>> print(f'foo{nl}bar')
foo
bar
>>> quote = '\''
>>> print(f'foo{quote}bar')
foo'bar
И наконец, выражение в f-строке, заключенное в тройные кавычки , не может содержать комментариев:
>>> z = 'bar'
>>> print(f'''foo{
... z
... }baz''')
foobarbaz
>>> print(f'''foo{
... z # Comment
... }''')
File "<stdin>", line 3
SyntaxError: f-string expression part cannot include '#'
Обратите внимание, что многострочная f-строка может содержать встроенные новые строки.
f-String Formatting
Как и метод Python .format()
, f-строки поддерживают множество модификаторов, которые управляют конечным видом выводимой строки. Есть и другие хорошие новости. Если вы освоили метод Python .format()
, то вы уже знаете, как использовать Python для форматирования f-строк!
Выражения в f-строках могут быть изменены с помощью <conversion>
или <format_spec>
, как и поля замены, используемые в шаблоне .format()
. Синтаксис идентичен. Фактически, в обоих случаях Python отформатирует поле замены с помощью одной и той же внутренней функции. В следующем примере !r
задается как компонент <conversion>
в строке шаблона .format()
:
>>> s = 'foo'
>>> '{0!r}'.format(s)
"'foo'"
Это заставляет выполнять преобразование с помощью repr()
. Вы можете получить практически тот же код, используя вместо него f-строку:
>>> s = 'foo'
>>> f'{s!r}'
"'foo'"
Все компоненты <format_spec>
, которые работают с .format()
, также работают с f-строками:
>>> n = 123
>>> '{:=+8}'.format(n)
'+ 123'
>>> f'{n:=+8}'
'+ 123'
>>> s = 'foo'
>>> '{0:*^8}'.format(s)
'**foo***'
>>> f'{s:*^8}'
'**foo***'
>>> n = 0b111010100001
>>> '{0:#_b}'.format(n)
'0b1110_1010_0001'
>>> f'{n:#_b}'
'0b1110_1010_0001'
Вложенность также работает, как и вложенные поля замены с помощью метода .format()
в Python:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux']
>>> w = 4
>>> f'{len(a):0{w}d}'
'0005'
>>> n = 123456789
>>> sep = '_'
>>> f'{(n * n):{sep}d}'
'15_241_578_750_190_521'
Это означает, что элементы форматирования могут быть оценены во время выполнения программы.
f-строки и метод Python .format()
- это, более или менее, два разных способа сделать одно и то же, причем f-строки - это более краткое сокращение. Следующие выражения по сути одинаковы:
f'{<expr>!<conversion>:<format_spec>}'
'{0!<conversion>:<format_spec>}'.format(<expr>)
Если вы хотите глубже изучить f-строки, то посмотрите Python 3's f-Strings: Улучшенный синтаксис форматирования строк (курс).
Заключение
В этом уроке вы освоили две дополнительные техники, которые можно использовать в Python для форматирования строковых данных. Теперь у вас есть все необходимые инструменты для подготовки строковых данных к выводу или отображению!
Возможно, вам интересно, какую технику форматирования в Python следует использовать. При каких обстоятельствах вы бы выбрали .format()
, а не f-string? См. раздел Python String Formatting Best Practices, чтобы узнать о некоторых соображениях, которые следует принять во внимание.
В следующем уроке вы узнаете больше о функциях в Python. На протяжении этой серии уроков вы видели множество примеров встроенных функций в Python. В Python, как и в большинстве языков программирования, вы можете определять свои собственные пользовательские функции. Если вам не терпится узнать, как это сделать, переходите к следующему уроку!
Вернуться на верх