Как мне отформатировать строку, используя словарь в python-3.x?


215

Я большой поклонник использования словарей для форматирования строк. Это помогает мне читать формат строки, который я использую, а также позволяет мне использовать существующие словари. Например:

class MyClass:
    def __init__(self):
        self.title = 'Title'

a = MyClass()
print 'The title is %(title)s' % a.__dict__

path = '/path/to/a/file'
print 'You put your file here: %(path)s' % locals()

Однако я не могу понять синтаксис Python 3.x для того же (или, если это вообще возможно). Я хотел бы сделать следующее

# Fails, KeyError 'latitude'
geopoint = {'latitude':41.123,'longitude':71.091}
print '{latitude} {longitude}'.format(geopoint)

# Succeeds
print '{latitude} {longitude}'.format(latitude=41.123,longitude=71.091)

Ответы:


16

Поскольку этот вопрос относится к Python 3, здесь используется новый синтаксис f-строки , доступный с Python 3.6:

>>> geopoint = {'latitude':41.123,'longitude':71.091}
>>> print(f'{geopoint["latitude"]} {geopoint["longitude"]}')
41.123 71.091

Обратите внимание на внешние одинарные кавычки и внутренние двойные кавычки (вы также можете сделать это наоборот).


Я бы сказал, что использование f-строки больше соответствует подходу python3.
Jonatas CD

2
Имейте в виду, что f-строки являются новыми для Python 3.6, а не в 3.5.
Хьюго

410

Это хорошо для тебя?

geopoint = {'latitude':41.123,'longitude':71.091}
print('{latitude} {longitude}'.format(**geopoint))

2
Попробовал это, и это сработало. Но я не понимаю использование «обозначения указателя». Я знаю, что Python не использует указатели, это пример kwargs?
Гомункул Ретикулли

2
@HomunculusReticulli Это параметр формата (минимальная ширина поля), а не указатель на стиль указателя C ++. docs.python.org/release/2.4.4/lib/typesseq-strings.html
Д.Розадо

29
Представлен Python 3.2 format_map. Аналогично str.format(**mapping), за исключением того, что mappingиспользуется напрямую и не копируется в dict. Это полезно, если, например mapping, подкласс dict
diapir

1
@eugene Что ** делает со словарем Python? Я не думаю, что он создает объект, потому что print (** геопункт) не дает синтаксической ошибки
Нитьеш Агарвал,

4
@NityeshAgarwal он распространяет словарь с именем = значение пары , как отдельные аргументы т.е. print(**geopoint)такой же , как print(longitude=71.091, latitude=41.123). Во многих языках это называется оператором сплат . В JavaScript это называется оператором распространения . В python нет конкретного имени, данного этому оператору.
abhisekp

79

Чтобы распаковать словарь в аргументы ключевого слова, используйте **. Кроме того, форматирование нового стиля поддерживает ссылки на атрибуты объектов и элементов отображений:

'{0[latitude]} {0[longitude]}'.format(geopoint)
'The title is {0.title}s'.format(a) # the a from your first example

2
Я нахожу этот ответ лучше, так как добавление позиционного индекса для заполнителя делает код более явным и более простым в использовании. Особенно, если у кого-то есть что-то вроде этого:'{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
Løiten

1
Это полезно, если вы используете defaultdictи у вас нет всех ключей
Whymarrh

65

Поскольку Python 3.0 и 3.1 являются EOL'ами, и никто не использует их, вы можете и должны использовать str.format_map(mapping)(Python 3.2+):

Похоже на str.format(**mapping), что сопоставление используется напрямую, а не копируется вdict . Это полезно, если, например, отображение является dictподклассом.

Это означает, что вы можете использовать, например, defaultdict , которая установит (и вернет) значение по умолчанию для отсутствующих ключей:

>>> from collections import defaultdict
>>> vals = defaultdict(lambda: '<unset>', {'bar': 'baz'})
>>> 'foo is {foo} and bar is {bar}'.format_map(vals)
'foo is <unset> and bar is baz'

Даже если предоставленное отображение - это dictне подкласс, это, вероятно, все равно будет немного быстрее.

Разница не большая, хотя, учитывая

>>> d = dict(foo='x', bar='y', baz='z')

затем

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format_map(d)

примерно на 10 нс (2%) быстрее, чем

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format(**d)

на моем Python 3.4.3. Разница, вероятно, будет больше, поскольку в словаре больше ключей, и


Обратите внимание, что язык форматирования гораздо более гибкий, чем этот; они могут содержать индексированные выражения, доступ к атрибутам и т. д., поэтому вы можете отформатировать целый объект или 2 из них:

>>> p1 = {'latitude':41.123,'longitude':71.091}
>>> p2 = {'latitude':56.456,'longitude':23.456}
>>> '{0[latitude]} {0[longitude]} - {1[latitude]} {1[longitude]}'.format(p1, p2)
'41.123 71.091 - 56.456 23.456'

Начиная с версии 3.6, вы также можете использовать интерполированные строки:

>>> f'lat:{p1["latitude"]} lng:{p1["longitude"]}'
'lat:41.123 lng:71.091'

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


Хороший, есть ли улучшения производительности по сравнению с format? (Учитывая, что это не копируется в диктовку)
Бхаргав Рао

2
@BhargavRao не очень, 2%: D
Антти Хаапала

@BhargavRao, если вы ищете производительность, используйте это '%(latitude)s %(longitude)s'%geopoint;)
Tcll


6

Синтаксис Python 2 работает и в Python 3:

>>> class MyClass:
...     def __init__(self):
...         self.title = 'Title'
... 
>>> a = MyClass()
>>> print('The title is %(title)s' % a.__dict__)
The title is Title
>>> 
>>> path = '/path/to/a/file'
>>> print('You put your file here: %(path)s' % locals())
You put your file here: /path/to/a/file

плюс он также заметно более производительный, чем f""или "".format();)
Tcll

2
geopoint = {'latitude':41.123,'longitude':71.091}

# working examples.
print(f'{geopoint["latitude"]} {geopoint["longitude"]}') # from above answer
print('{geopoint[latitude]} {geopoint[longitude]}'.format(geopoint=geopoint)) # alternate for format method  (including dict name in string).
print('%(latitude)s %(longitude)s'%geopoint) # thanks @tcll

1
вы пропустили один;) print('%(latitude)s %(longitude)s'%geopoint)это также значительно быстрее, чем другие 2
Tcll

@tcll На самом деле я хотел примеры, где я могу использовать имя словаря внутри строки. Как то так'%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
Шейх Абдул Вахид

1

В большинстве ответов форматируются только значения из dict.

Если вы также хотите отформатировать ключ в строку, вы можете использовать dict.items () :

geopoint = {'latitude':41.123,'longitude':71.091}
print("{} {}".format(*geopoint.items()))

Вывод:

(«широта», 41.123) («долгота», 71.091)

Если вы хотите выполнить произвольное форматирование, то есть не показывать значения ключей, такие как кортежи:

from functools import reduce
print("{} is {} and {} is {}".format(*reduce((lambda x, y: x + y), [list(item) for item in geopoint.items()])))

Вывод:

широта 41.123 и долгота 71.091


обратите внимание, что есть шанс, что «долгота» может появиться раньше, чем «широта» geopoint.items();)
Tcll
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.