Форматирование defaultdict с распаковкой ключевых слов **

Я хочу отформатировать и распечатать данные из словаря с оператором распаковки ключевых слов **,

Строка формата, возможно, ссылается на множество ключевых слов, а в словаре могут отсутствовать все необходимые ключи. Для отсутствующих ключей я хотел бы использовать строку "N / A" в качестве значения по умолчанию.

Я хотел бы найти умное решение этой проблемы по умолчанию, возможно, используя defaultdict,

Вот первое решение с использованием регулярного dict,

# Cumbersome solution with dict
format_str = '{date} {version} {comment}'
data       = dict()

data['date']    = 'today'
data['version'] = 'v1'
data['comment'] = 'N/A'  # I want to avoid this

print format_str.format(**data)
# prints: today v1 N/A

Я хотел бы избежать явного назначения 'N/A' для отсутствующих ключей.

Следующее решение также использует обычный dict и анализирует строку формата для построения списка ключевых слов:

# Another solutions with handmade defaults for missing keys
format_str = '{date} {version} {comment}'
data       = dict()

data['date']    = 'today'
data['version'] = 'v1'

import re
for k in re.findall('{(\w+)}', format_str):
    if k not in data:
        data[k] = 'N/A'

print format_str.format(**data)
# prints: today v1 N/A

Это решение с re.findall не очень элегантно и не надежно, так как синтаксис строки формата намного сложнее, чем выше {(\w+)},

Следующее решение будет моим любимым… если оно не потерпит неудачу по очевидной причине.

# Failed attempt with defaultdict
from collections import defaultdict
format_str = '{date} {version} {comment}'
data       = defaultdict(lambda x:'N/A')

data['date']    = 'today'
data['version'] = 'v1'

print format_str.format(**data)
# raises KeyError: 'comment'

Проблема здесь в том, что ** на самом деле распаковывает ключевые слова в data, так format не ищет data для запрошенных ключевых слов и, следовательно, не дает data возможность предоставить его значение по умолчанию.

Есть ли этому решение? Например, есть ли альтернатива format функция, которая на самом деле вызовет data.get(kwd) и, таким образом, получить N/As?

2 ответа

Решение

Использование string.Formatter.vformat() и передать defaultdict к этому.

from collections import defaultdict
from string import Formatter

fmtr = Formatter()
format_str = '{date} {version} {comment}'
data = defaultdict(lambda: 'N/A')

data['date'] = 'today'
data['version'] = 'v1'

print fmtr.vformat(format_str, (), data)

Хорошее решение с использованием форматера уже дано

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

format_str = '{date} {version} {comment}'

И dict, как и предполагалось, уже поддерживает сопоставление ключевых слов и значений.

так что для таких как

>>> d
{'version': 'v1', 'date': 'today'}

используя значение по умолчанию для dict.get()

>>> print '{} {} {}'.format(d['date'],d['version'],d.get('comment','n/a'))
today v1 n/a

если вы хотите управление ключевыми словами в одном месте (как вы делали со строкой форматирования), я бы попробовал что-то вроде этого

>>> f=lambda x: (x.get('date'),x.get('version'),x.get('comment','N/A'))
>>> print '{} {} {}'.format(*f(d))
today v1 N/A

или это

>>> f=lambda x: '{} {} {}'.format(x['date'],x['version'],x.get('comment','N/A'))
>>> print f(d)
today v1 N/A

выгода есть, меньше импорт

Другие вопросы по тегам