[ `"...".format(**ctx)` which skips unknown keys? ]
Is it possible to create a dict-like object that can be used in str.format()
and that leaves unknown substitutions, i.e.:
ctx = Context(source='foo', name='bar')
print "{source}/static/{name}-{version}.min.css".format(**ctx)
should print
"foo/static/bar-{version}.min.css"
I tried with a simple dict
subclass:
class Context(dict):
def __getitem__(self, k):
if k not in self: return '{%s}' % k
return dict.__getitem__(self, k)
but that errors with KeyError: 'version'
Answer 1
Python 3 introduced str.format_map
for this:
class Context(dict):
def __missing__(self, key):
return '{%s}' % key
ctx = Context(source='foo', name='bar')
print("{source}/static/{name}-{version}.min.css".format_map(ctx))
prints
foo/static/bar-{version}.min.css
One of the changes involved in adding format_map
had the probably-unintended side effect that Python 3's str.format
will also accept dict subclasses, but mappings that don't subclass dict
need to be passed to format_map
. I believe this new behavior of str.format
is technically a bug. In any case, format_map
is probably safer.
For Python 2, the issue on the Python bug tracker leading to str.format_map
's inclusion suggests using string.Formatter.vformat
:
import string
print string.Formatter().vformat("{source}/static/{name}-{version}.min.css", (), ctx)
Answer 2
class Context(dict):
def __getitem__(self, k):
return self.get(k, '{%s}' % k)
>>> ctx = Context(source='foo', name='bar')
>>>
>>> print("{source}/static/{name}-{version}.min.css".format(**ctx))
foo/static/bar-{version}.min.css