Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use a dynamic mapping to unpack keyword arguments in Python?

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?

like image 985
Aaron McMillin Avatar asked Nov 21 '11 21:11

Aaron McMillin


2 Answers

In Python 2 you can do this using string.Formatter class.

>>> class Mapping(object):
...     def __getitem__(self, key):
...         return 'Proxied: %s' % key
...
>>> my_mapping = Mapping()
>>> from string import Formatter
>>> Formatter().vformat('{Thing1} and {other_thing}', (), my_mapping)
'Proxied: Thing1 and Proxied: other_thing'
>>>

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 ().

like image 146
yak Avatar answered Oct 13 '22 02:10

yak


Python 3.2+:

'{Thing1} and {other_thing}'.format_map(my_mapping)
like image 26
jfs Avatar answered Oct 13 '22 02:10

jfs