让kwargs直接访问

时间:2013-11-21 08:41:19

标签: python arguments kwargs

我正在重构一段代码,我遇到了以下问题。我有一个巨大的参数列表,现在我希望将其作为kwargs传递。代码是这样的:

def f(a, b, c, ...):
  print a
  ...

f(a, b, c, ...)

我正在重构它:

data = dict(a='aaa', b='bbb', c='ccc', ...)
f(**data)

这意味着我必须这样做:

def f(**kwargs):
  print kwargs['a']
  ...

但这是皮塔饼。我想保留:

def f(**kwargs):
  # Do some magic here to make the kwargs directly accessible
  print a
  ...

有没有直接的方法可以直接访问kwargs dict中的参数,也许是通过使用一些帮助类/库?

6 个答案:

答案 0 :(得分:7)

some ways - 但你也可以像这样包装你的函数:

def f(**kwargs):
    arg_order = ['a', 'b', 'c', ...]
    args = [kwargs.get(arg, None) for arg in arg_order]

    def _f(a, b, c, ...):
        # The main code of your function

    return _f(*args)

样品:

def f(**kwargs):
    arg_order = ['a', 'b', 'c']
    args = [kwargs.get(arg, None) for arg in arg_order]

    def _f(a, b, c):
        print a, b, c

    return _f(*args)

data = dict(a='aaa', b='bbb', c='ccc')
f(**data)

输出:

>>> 
aaa bbb ccc

答案 1 :(得分:3)

好吧,您可以手动更新locals,但文档会特别警告它。

for key, value in kwargs.iteritems(): #Python 2.7 here
    locals()[key] = value

另一种选择是使用exec,虽然通常不赞成,但至少可以保证正常工作。

for key, value in kwargs.iteritems(): #Python 2.7 here
    exec('{} = value'.format(key)

虽然我不会向任何人承认你实际上做过其中任何一项。

答案 2 :(得分:1)

功能内部:

for k, v in kwargs.iteritems():
    locals()[k] = v

答案 3 :(得分:1)

我必须在类似情况下重构我的代码,并且我不同意使用kwargs['a'],这感觉有点尴尬。有时我使用bunch对象而不是字典,这允许您通过属性访问(params.a)而不是字典查找来访问字段。每次使用参数时,它只为您节省3个字符,但我发现它更好看,因为您不需要参数名称周围的引号。有各种各样的食谱来实现一个,参见例如these ones

所以不要像你的情况那样使用dict,而是像

一样使用它
In [1]: class Bunch:
   ...:     def __init__(self, **kwds):
   ...:         self.__dict__.update(kwds)

In [2]: params = Bunch(a = 'aaa', b = 'bbb')

In [3]: def f(p):
   ...:     print p.a
   ...:     

In [4]: f(params)
aaa

我知道这不是你问题的直接答案,但它只是使用kwargs的另一种选择。

答案 4 :(得分:1)

另一种可能的方法(基于您的评论here)是使用属性字典:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr] if attr in self.keys() else None
    def __setattr__(self, attr, value):
        self[attr] = value 

要像这样使用:

def f(**kwargs):
    kwargs = AttributeDict(kwargs)

样品:

def f(**kwargs):
    kwargs = AttributeDict(kwargs)
    print kwargs.a, kwargs.b, kwargs.c

data = dict(a='aaa', b='bbb', c='ccc')
f(**data)

输出:

>>> 
aaa bbb ccc

注意:如果您想要更短的变量名称,则可以随时为其命名x,然后访问权限只有x.a

答案 5 :(得分:0)

在我看来,你正在做冗员和最简单的解决方案。那些a, b, c是关键字参数和位置,因此您可以按照自己喜欢的方式调用函数:

>>> def f(a, b, c=3):
...     print a, b, c

使用所有关键字参数

>>> f(**{'a':1, 'b':2}) 
1 2 3

混合使用位置和关键字args

>>> f(5, **{'b':4})
5 4 3

如果错误的关键字args

,则会收到正确的错误
>>> f(**{'d':4, 'a':1, 'b':2}) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'd'