Як відформатувати рядок за допомогою словника в 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)

Відповіді:


15

Оскільки питання стосується Python 3, тут використовується новий синтаксис f-string , доступний з Python 3.6:

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

Зверніть увагу на зовнішні одиночні лапки та внутрішні подвійні лапки (ви також можете це зробити навпаки).


Я б сказав, що використання f-string більше узгоджується з підходом python3.
CD Jonatas

2
Майте на увазі, що f-рядки є новими для Python 3.6, а не 3.5.
Гюго

409

Це добре для вас?

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

2
Спробував це, і це спрацювало. Але я не розумію використання "позначення покажчика". Я знаю, що Python не використовує покажчиків, це приклад кваргів?
Homunculus Reticulli

2
@HomunculusReticulli Це параметр формату (Мінімальна ширина поля), а не вказівник на стиль C ++ вказівника. docs.python.org/release/2.4.4/lib/typesseq-strings.html
D.Rosado

29
Введено Python 3.2 format_map. Подібний str.format(**mapping), за винятком того, що mappingвикористовується безпосередньо та не копіюється в a dict. Це корисно, якщо, наприклад, mappingє підклас
диктату

1
@eugene Що робить ** зі словника python? Я не думаю, що він створює об’єкт, оскільки при друку (** геоточка) не вдається дати синтаксичну помилку
Nityesh Agarwal

4
@NityeshAgarwal поширює словник з парами name = значення як окремі аргументи, тобто print(**geopoint)таке ж, як print(longitude=71.091, latitude=41.123). У багатьох мовах він відомий як оператор splat . У 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'ed, і ніхто їх не використовує, ви можете і повинні використовувати str.format_map(mapping)(Python 3.2+):

Подібно до str.format(**mapping), за винятком того, що відображення використовується безпосередньо, а не скопійовано в adict . Це корисно, якщо, наприклад, картографування є 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? (Враховуючи, що він не скопійований у дікт)
Bhargav Rao

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.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.