将一个传递的字典"解压缩"到Python中函数的名称空间中?

And*_*ner 30 python parameters dictionary function

在我的工作中,为了方便起见,我经常需要将参数分组到子集中:

d1 = {'x':1,'y':2}
d2 = {'a':3,'b':4}
Run Code Online (Sandbox Code Playgroud)

我通过传入多个词典来做到这一点.大多数时候我直接使用传递的字典,即:

def f(d1,d2):
    for k in d1:
        blah( d1[k] )
Run Code Online (Sandbox Code Playgroud)

在某些函数中,我需要直接访问变量,事情变得很麻烦; 我真的想在本地名称空间中使用这些变量.我希望能够做到这样的事情:

def f(d1,d2)
    locals().update(d1)
    blah(x)
    blah(y)    
Run Code Online (Sandbox Code Playgroud)

但是locals()返回的字典更新并不能保证实际更新命名空间.

这是明显的手动方式:

def f(d1,d2):
    x,y,a,b = d1['x'],d1['y'],d2['a'],d2['b']
    blah(x)
    return {'x':x,'y':y}, {'a':a,'b':b}
Run Code Online (Sandbox Code Playgroud)

这导致每个函数重复三次参数列表.这可以通过装饰器自动完成:

def unpack_and_repack(f):
    def f_new(d1, d2):
        x,y,a,b = f(d1['x'],d1['y'],d2['a'],d3['b'])
        return {'x':x,'y':y}, {'a':a,'b':b}
    return f_new
@unpack
def f(x,y,a,b):
    blah(x)
    blah(y)
    return x,y,a,b
Run Code Online (Sandbox Code Playgroud)

这导致装饰器重复三次,每个功能加两次,所以如果你有很多功能,那就更好了.

有没有更好的办法?也许使用eval的东西?谢谢!

Bea*_*ear 30

您始终可以将字典作为参数传递给函数.例如,

dict = {'a':1, 'b':2}
def myFunc(a=0, b=0, c=0):
    print(a,b,c)
myFunc(**dict)
Run Code Online (Sandbox Code Playgroud)


Jou*_*nen 10

如果您更喜欢d.variable语法d['variable'],可以将字典包装在一个几乎无关紧要的"束"对象中,例如:

class Bunch:
    def __init__(self, **kw):
        self.__dict__.update(kw)
Run Code Online (Sandbox Code Playgroud)

它并没有将字典内容完全带入本地命名空间,但如果对对象使用短名称则会接近.


Tha*_*ava 7

假设字典中的所有键都有资格成为标识符,您可以这样做:

adict = { 'x' : 'I am x', 'y' : ' I am y' }
for key in  adict.keys():
  exec(key + " = adict['" + key + "']")
blah(x)
blah(y)
Run Code Online (Sandbox Code Playgroud)

  • 在此之后,IDE将无法理解x和y是有效变量. (2认同)

unu*_*tbu 5

这与装饰器的想法类似,但是更通用一些,因为它允许您将任意数量的dict传递给foo,并且装饰器不必了解有关dict中的键或参数顺序的任何信息调用基础foo函数时。

#!/usr/bin/env python
d1 = {'x':1,'y':2}
d2 = {'a':3,'b':4}

def unpack_dicts(f):
    def f_new(*dicts):
        new_dict={}
        for d in dicts:
            new_dict.update(d)
        return f(**new_dict)
    return f_new

@unpack_dicts
def foo(x,y,a,b):
    print x,y,a,b

foo(d1,d2)
# 1 2 3 4
Run Code Online (Sandbox Code Playgroud)