我可以使用动态映射来解压缩Python中的关键字参数吗?

时间:2011-11-21 21:18:52

标签: python keyword-argument

长话短说,我想用任意命名的参数调用格式,这将形成一个查找。

'{Thing1} and {other_thing}'.format(**my_mapping)

我尝试过像这样实现my_mapping:

class Mapping(object):
  def __getitem__(self, key):
    return 'Proxied: %s' % key
my_mapping = Mapping()

调用my_mapping['anything']时,其工作正常。但是当传递给如上所示的format()时,我得到:

TypeError: format() argument after ** must be a mapping, not Mapping

我尝试了对dict进行子类化,而不是object,但现在调用format()会显示KeyError。我甚至将__contains__实施为return True,但仍然KeyError

所以**似乎不只是在传入的对象上调用__getitem__。有人知道怎么解决这个问题吗?

4 个答案:

答案 0 :(得分:6)

在Python 2中,您可以使用string.Formatter类来完成此操作。

>>> 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需要3个参数:格式字符串,位置字段序列和关键字字段的映射。由于不需要位置字段,我使用了空元组()

答案 1 :(得分:5)

Python 3.2 +:

'{Thing1} and {other_thing}'.format_map(my_mapping)

答案 2 :(得分:2)

这可能有点神秘,但我最近遇到了这个问题,这个问题是第一个结果。我对使用string.Formatter感到不满意,并希望 Just Work (TM)

如果您为班级和keys()实施__getitem__()功能,那么**my_mapping将有效。

即:

class Mapping(object):

  def __getitem__(self, key):
    return 'Proxied: %s' % key

  def keys(self):
    return proxy.keys()

,其中

>>> my_mapping = Mapping()
>>> my_mapping.keys()
['Thing1','other_thing',...,'Thing2']

将导致成功的映射与.format一起使用。

显然(虽然我实际上没有查看str.format的源代码),它似乎使用keys()来获取密钥列表,然后将字符串中给出的标识符映射到这些密钥,然后使用__getitem__()检索指定的值。

希望这有帮助。

修改

如果你在@ aaron-mcmillin的位置,并且密钥集很大,那么可能的方法是不生成一整套密钥,而是生成一个较小的子集。这当然只有你知道你只需要格式化一个小子集。

即:

class Mapping(object):
  ...
  def keys(self):
    return ['Thing1','other_thing', 'Thing2']

答案 3 :(得分:1)

这是我能想到的最好的:

如果你有一个自定义映射对象要传递给一个带有关键字参数的func,那么它必须有一组键(可以动态生成,但它必须是有限集),并且它必须能够以某种方式映射这些键。因此,如果您可以假设它将获得__iter__来获取密钥,并且__getitem__将成功获得每个密钥,例如:

class Me(object):
    def __init__(self):
        pass

    def __iter__(self):
        return iter(['a', 'b', 'c'])

    def __getitem__(self, key):
        return 12

说功能是:

def myfunc(**kwargs):
    print kwargs, type(kwargs)

然后我们可以通过制作一个词典来传递它:

m = Me()
myfunc(**dict((k, m[k]) for k in m))

导致:

{'a': 12, 'c': 12, 'b': 12} <type 'dict'>

显然这必须是它完成的方式......即使你传入一个派生自dict的对象,该函数仍然会有一个dict的kwargs:

class Me(dict): pass

m = Me()
print type(m) #prints <class '__Main__.Me'>

def myfunc(**kwargs):
    print type(kwargs)
myfunc(**m) #prints <type 'dict'>

因为听起来你想要做一些事情,比如根据键是什么来返回一个值,没有特定的键集,似乎你不能使用format函数。