Руководство по форматированию строк с помощью Python

Оглавление

Форматирование строк является надежной и мощной частью инструментария любого программиста на Python - почти каждая часть производственного программного обеспечения так или иначе использует его преимущества. Однако средства форматирования строк сильно изменились за время существования Python. От форматирования %, метода format() до форматированных строковых литералов - возможности форматирования строк не ограничены.

Компоновка формы и содержания строк во время выполнения - это базовая возможность любого языка высокого уровня. Вставляете ли вы значения переменных в сообщение журнала, формируете вывод на основе пользовательского ввода или создаете сообщения для клиента с использованием временной метки - вам часто понадобится эта функция. На базовом уровне вы можете конкатенировать строки, просто используя +, но это неэффективно, а также трудно сделать выразительным. Именно здесь на помощь приходят возможности Python по форматированию строк.

Старый способ: printf стилевое форматирование.

Один из первоначальных способов форматирования строк в Python был основан на соглашении, используемом в printf. Вставка значения в строку осуществлялась путем представления его в виде %, за которым следовал символ, указывающий на его тип. Итак, для вставки строки и целого числа:

>>> this = "this"
>>> five = 5
>>> "%s is a %d" % (this, five)
'this is a 5'

%d вызовет ошибку типа TypeError, если входные данные не являются целым числом. %s - это то же самое, что и вызов str() на входе. Это можно использовать с любым объектом, а не только со строками:

>>> "%s is a list" % [1,2,3]
'[1, 2, 3] is a list'

%r - это то же самое, что вызов repr() на вход, в отличие от %s:

>>> "%s sounds like %r" % ("Seaweed", "Seaweed")
"Seaweed sounds like 'Seaweed'"

При использовании плавающих цифр количество отображаемых цифр можно контролировать путем вставки этого числа:

>>> "%.3f" % 6.1234567
'6.123'

Обратите внимание, что при усечении цифр значение не округляется. Для добавления вставки к строкам добавьте количество вставки следующим образом:

>>> for w in ['some', 'words', 'are', 'longer']:
...     print("|%15s" % w)
...
|           some
|          words
|            are
|         longer

Словарь также можно использовать для вставки значений в строку:

>>>  ship_info = {'ship': 'personiples', 'captain': 'Archaeus'}
>>> "%(ship)s was run hard by %(captain)s" % ship_info
'personiples was run hard by Archaeus'

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

Python 3: str.format()

В Python 3 был представлен новый способ форматирования строк: метод str.format(), использующий мини-язык спецификации формата, который предлагал более мощное форматирование. Это было перенесено в Python 2.6.

В этой новой спецификации для указания полей замены используются фигурные скобки, а не %s В стиле %. Позиция аргументов определяет позицию в целевой строке, что может быть сделано и в стиле str.format():

>>> "{} comes before {}".format('a','b')
'a comes before b'

Теперь мы можем также указать индекс аргумента, что позволяет повторять и менять порядок исходных аргументов:

>>> "{1} is after {0} which is before {1}".format('a','b')
'b is after a which is before b'

Еще более интересной является возможность доступа к аргументам по имени:

>>> "{cat} loves {dog}, {dog} loves {cat}".format(cat='Whiskers', dog='Rover')
'Whiskers loves Rover, Rover loves Whiskers'

Этот механизм можно использовать в сочетании со словарями:

>>> ship_captains = {'The Irish Rover': 'Mick McCann', 'Davey Crockett': 'Burgess'}
>>> "{Davey Crockett} and {The Irish Rover} are both ship captains".format(**ship_captains)
'Burgess and Mick McCann are both ship captains'

Поле замены может содержать любое выражение, включая доступ к атрибутам объекта:

>>> class Ship:
...     def __init__(self, name, masts, captain):
...         self.name = name
...         self.masts = masts
...         self.captain = captain
...
...     def __str__(self):
...         msg = "{self.name} had {self.masts} masts and was captained by {self.captain}"
...         return  msg.format(self=self)
...
>>> ships = [ Ship("The Irish Rover", 27, 'Mick McCann'),
...           Ship("Davey Crockett", 3, 'Burgess'),
...           Ship("The John B", 2, 'Richard Le Gallienne') ]
>>>
>>> for ship in ships:
...          print(ship)
...
The Irish Rover had 27 masts and was captained by Mick McCann
Davey Crockett had 3 masts and was captained by Burgess
The John B had 2 masts and was captained by Richard Le Gallienne

Наконец, мы можем добавить аргументы спецификации формата после имени поля или индекса - например, для выравнивания мы можем использовать > или <, за которыми следует желаемый padding:

>>> for ship in ships:
...   print("|{ship.name:>22}|{ship.captain:>22}|{ship.masts:>22}|".format(ship=ship))
...
|       The Irish Rover|           Mick McCann|                    27|
|        Davey Crockett|               Burgess|                     3|
|            The John B|  Richard Le Gallienne|                     2|

Новый стандарт: f-строки (f-string)

Хотя метод str.format менее подвержен ошибкам, чем стиль printf, он все же не является наиболее интуитивно понятным для использования. Гораздо более читабельным и интуитивно понятным решением является использование f-строк. Форматированные строковые литералы, или f-строки, были введены в Python 3.6 и являются интересным дополнением к нашему арсеналу. Они обозначаются символами f или F перед открывающей кавычками строкой. Они позволяют нам использовать те же поля замены, что и str.format(), но при этом выражения в этих полях будут находиться в текущей среде, а не передаваться в метод format.

>>> strings_count = 5
>>> frets_count = 21
>>> f"My banjo has {strings_count} strings and {frets_count} frets"
'My banjo has 5 strings and 21 frets

Здесь видно, что мы сослались на переменные strings_count и frets_count внутри f-строки. Мы можем использовать выражения, которые обращаются к содержимому списка в полях замены:

>>> arrivals = ['The Irish Rover', 'The Titanic', 'The Rueben']
>>> f'The first to arrive was {arrivals[0]} and the last was {arrivals[-1]}'
'The first to arrive was The Irish Rover and the last was The Rueben'

За выражением следует поле преобразования, представленное типом преобразования, которому предшествует символ !. Чтобы использовать форму repr() в строке, используйте поле преобразования !r :

>>> ship_name = "Davey Crockett"
>>> f'The ships name was spelled {ship_name!r}'
"The ships name was spelled 'Davey Crockett'"

Это то же самое, что вызвать repr() напрямую:

>>> f'The ships name was spelled {repr(ship_name)}'
"The ships name was spelled 'Davey Crockett'"

Также существует тип преобразования для функции ascii():

>>> check = “√”
>>> f"The ascii version of {check} is {check!a}"
"The ascii version of √ is '√'"

Мы также можем вложить поля:

>>> rag_count = 1000000
>>> padding = 10
>>> f'Sligo rags: {rag_count:{padding}d}'
'Sligo rags:    1000000'

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

С появлением F-строк у нас появилось мощное, интуитивно понятное и читаемое решение. Программистам на python, которые хотят узнать больше, я бы посоветовал посмотреть документацию по мини-языку format string и открыть оболочку, чтобы попробовать f-строки с различными вариантами формата - это действительно интересное и мощное нововведение.

Вернуться на верх