I want to format and print data from a dictionary with the keyword unpacking operator **.
The format string possibly refers to many keywords and the dictionary may not have all the required keys. For the missing keys, I would like to use the string 'N/A' as a default value.
I would like a clever solution for this default-ing problem, possibly using a defaultdict.
Here is a first solution using a regular 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
I would like to avoid the explicit assignment of 'N/A' for missing keys.
The following solution also uses a regular dict and analyzes the format string to build the list of keywords:
# 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
This solution with re.findall is not really elegant nor robust since the syntax of format string is much more complex than the above {(\w+)}.
The following solution would be my favorite one… if it did not fail for an obvious reason.
# 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'
The problem here is that ** actually unpacks the keywords in data, so format does not search data for the requested keywords and thus does not give data the opportunity to provide its default value.
Is there a solution to this ?
Eg is there an alternative format function which would actually call data.get(kwd) and thus get the N/As?