Leaving values blank if not passed in str.format
Solution 1
You can follow the recommendation in PEP 3101 and use a subclass Formatter:
import string
class BlankFormatter(string.Formatter):
def __init__(self, default=''):
self.default=default
def get_value(self, key, args, kwds):
if isinstance(key, str):
return kwds.get(key, self.default)
else:
return string.Formatter.get_value(key, args, kwds)
kwargs = {"name": "mark", "adj": "mad"}
fmt=BlankFormatter()
print fmt.format("My name is {name} and I'm really {adj}.", **kwargs)
# My name is mark and I'm really mad.
print fmt.format("My name is {name} and I'm really {adjective}.", **kwargs)
# My name is mark and I'm really .
As of Python 3.2, you can use .format_map as an alternative:
class Default(dict):
def __missing__(self, key):
return '{'+key+'}'
kwargs = {"name": "mark"}
print("My name is {name} and I'm really {adjective}.".format_map(Default(kwargs)))
which prints:
My name is mark and I'm really {adjective}.
Solution 2
Here is one option which uses collections.defaultdict
:
>>> from collections import defaultdict
>>> kwargs = {"name": "mark"}
>>> template = "My name is {0[name]} and I'm really {0[adjective]}."
>>> template.format(defaultdict(str, kwargs))
"My name is mark and I'm really ."
Note that we aren't using **
to unpack the dictionary into keyword arguments anymore, and the format specifier uses {0[name]}
and {0[adjective]}
, which indicates that we should perform a key lookup on the first argument to format()
using "name"
and "adjective"
respectively. By using defaultdict
a missing key will result in an empty string instead of raising a KeyError.
Related videos on Youtube
marky1991
Updated on June 04, 2022Comments
-
marky1991 almost 2 years
I've run into a fairly simple issue that I can't come up with an elegant solution for.
I'm creating a string using
str.format
in a function that is passed in adict
of substitutions to use for the format. I want to create the string and format it with the values if they're passed and leave them blank otherwise.Ex
kwargs = {"name": "mark"} "My name is {name} and I'm really {adjective}.".format(**kwargs)
should return
"My name is mark and I'm really ."
instead of throwing a
KeyError
(Which is what would happen if we don't do anything).Embarrassingly, I can't even come up with an inelegant solution for this problem. I guess I could solve this by just not using
str.format
, but I'd rather use the built-in (which mostly does what I want) if possible.Note: I don't know in advance what keys will be used. I'm trying to fail gracefully if someone includes a key but doesn't put it in the kwargs dict. If I knew with 100% accuracy what keys would be looked up, I'd just populate all of them and be done with it.
-
marky1991 over 10 yearsThe indexing solution isn't (aesthetically) pretty, but you're right, it works as I want.
-
marky1991 over 10 yearsHmm. This is interesting. I think I'll actually go this route. I'm still not a fan of the ugly indexing that the other answer uses. Thanks for the suggestion!
-
Elias Zamaria over 7 yearsI am a bit confused. Shouldn't
Formatter
bestring.Formatter
? Can thatelse
part even be reached? -
dawg about 7 years@EliasZamaria: Yes, it should have been
return string.Formatter
and that has been corrected. Theelse
is reached if you use tuple indexing formatting like"one {0} two {1}".format(1,2)
instead of keyword access. Thanks for the comment. Three year old bug fixed! -
IvanD over 5 yearsThis is the simplest solution that I've found. It can also be a one-liner: "My name is {0[name]} and I'm really {0[adjective]}.".format(defaultdict(str, kwargs)) Beautiful!