Long story short, I want to call format with arbitrarily named arguments, which will preform a lookup.
'{Thing1} and {other_thing}'.format(**my_mapping)
I've tried implementing my_mapping like this:
class Mapping(object):
def __getitem__(self, key):
return 'Proxied: %s' % key
my_mapping = Mapping()
Which works as expected when calling my_mapping['anything']
. But when passed to format() as shown above I get:
TypeError: format() argument after ** must be a mapping, not Mapping
I tried subclassing dict
instead of object
, but now calling format()
as shown raises KeyError
. I even implemented __contains__
as return True
, but still KeyError
.
So it seems that **
is not just calling __getitem__
on the object passed in. Does anyone know how to get around this?
Python 3.2+:
In Python 2 you can do this using
string.Formatter
class.vformat
takes 3 args: the format string, sequence of positional fields and mapping of keyword fields. Since positional fields weren't needed, I used an empty tuple()
.This is the best I could come up with:
If you have a custom mapping object that you want to pass to a func taking key-word arguments, then it must have a set of keys (which may be dynamically generated, but it must be a finite set), and it must be able to map those keys somehow. So, if you can assume that it will have an
__iter__
to get the keys, and a__getitem__
that will succeed for each of those keys, e.g.:Say the function is:
Then we can pass it along by making a dict:
Resulting in:
Apparently this must be the way it's done... even if you pass in an object derived from
dict
, the function will still have adict
for the kwargs:Since it sounds like you wanted to do something like return a value based on what the key was, without having a particular set of keys in mind, it seems like you can't use the
format
function.This may be a bit of necromancy, but I recently came across this problem, and this SO question was the first result. I wasn't happy with using
string.Formatter
, and wanted it to Just Work (TM).If you implement a
keys()
function for your class as well as__getitem__()
, then**my_mapping
will work.I.e:
where
will result in a successful mapping that will work with
.format
.Apparently (though I haven't actually looked at the source for
str.format
), it appears to usekeys()
to get a list of keys, then map the identifiers given in the string to those keys, then use__getitem__()
to retrieve the specified values.Hope this helps.
EDIT:
If you are in @aaron-mcmillin's position, and the key set is large, then a possible approach is to not generate a full set of keys, but generate a smaller subset. This only works of course if you know you will only need to format a small subset.
I.e: