在我的工作中,为了方便起见,我经常需要将参数分组到子集中:
d1 = {'x':1,'y':2}
d2 = {'a':3,'b':4}
我通过传入多个词典来做到这一点。大多数时候我直接使用传递的字典,即:
def f(d1,d2):
for k in d1:
blah( d1[k] )
在某些函数中,我需要直接访问变量,事情变得很麻烦;我真的想在本地名称空间中使用这些变量。我希望能够做到这样的事情:
def f(d1,d2)
locals().update(d1)
blah(x)
blah(y)
但是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}
这导致每个函数重复三次参数列表。这可以通过装饰器自动完成:
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
这导致装饰器重复三次,每个功能加两次,所以如果你有很多功能,那就更好了。
有更好的方法吗?也许使用eval的东西?谢谢!
答案 0 :(得分:29)
您始终可以将字典作为参数传递给函数。例如,
dict = {'a':1, 'b':2}
def myFunc(a=0, b=0, c=0):
print(a,b,c)
myFunc(**dict)
答案 1 :(得分:10)
如果您希望d.variable
语法优于d['variable']
,则可以将字典包装在an almost trivial "bunch" object中,例如:
class Bunch:
def __init__(self, **kw):
self.__dict__.update(kw)
它并没有将字典内容完全带入本地命名空间,但如果对对象使用短名称则会关闭。
答案 2 :(得分:7)
假设词典中的所有键都有资格成为标识符, 你可以这样做:
adict = { 'x' : 'I am x', 'y' : ' I am y' }
for key in adict.keys():
exec(key + " = adict['" + key + "']")
blah(x)
blah(y)
答案 3 :(得分:5)
这类似于你的装饰者的想法,但它更通用,因为它允许你传递任意数量的dicts到foo
,并且装饰者不必知道关于键的任何信息。调用基础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
答案 4 :(得分:4)
这是我用作locals().update(d1)
解决方法的内容:
def f(d1,d2)
exec ','.join(d1) + ', = d1.values()'
blah(x)
blah(y)
答案 5 :(得分:3)
这是一个单行内容的解包方法:
x,y = (lambda a,b,**_: (a,b))(**{'a':'x', 'b':'y', 'c': 'z'})
lambda args a
和b
是我想按顺序解压缩到x
和y
的密钥。 **_
可以忽略字典中的任何其他键,即c
。
答案 6 :(得分:2)
我认为你不能为Python中的dict解压缩获得更多便利。所以,这里有强制性的“如果疼,不要那样做”答案。
映射项访问比Python中的属性访问更麻烦,所以也许你应该传递用户定义类的实例而不是dicts。
答案 7 :(得分:2)
我认为常识是“不要在生产代码中使用inspect
模块”,我大多同意这一点。因此,我认为在生产代码中执行以下操作是个坏主意。但是,如果你正在开发一个支持帧的python(比如CPython),这个应该工作:
>>> def framelocals():
... return inspect.currentframe(1).f_locals
...
>>> def foo(ns):
... framelocals().update(ns)
... print locals()
...
>>> foo({'bar': 17})
{'ns': {'bar': 17}, 'bar': 17}
它只是抓取调用者框架中的实际dict
,当在函数体内调用时,它应该是函数的名称空间。我不知道在使用CPython时是否存在或不存在locals()
不仅仅是这样做的情况;文档中的警告可能是“修改dict
返回的locals()
的效果取决于python实现”。因此,虽然它可以在CPython中修改dict
,但它可能不在另一个实现中。
更新:此方法实际上无效。
>>> def flup(ns):
... framelocals().update(ns)
... print locals()
... print bar
...
>>> flup({'bar': 17})
{'ns': {'bar': 17}, 'bar': 17}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in flup
NameError: global name 'bar' is not defined
正如ddaa建议的那样,函数编译中有一些更深层次的魔术,它记录了局部变量。因此,您可以更新dict
,但无法通过正常的本地命名空间查找来查看更新。
答案 8 :(得分:1)
为此,我经常使用.items()方法保持安静。
def unpack(dict):
for key, value in dict.items():
print(key, value)
答案 9 :(得分:0)
我编写了一个名为var_arguments的Python包,用于方便地捆绑和解绑在这里应该有用的参数;它可用on github。
而不是写作,说:
def f(d1,d2):
x,y,a,b = d1['x'],d1['y'],d2['a'],d2['b']
y=x+a
return {'x':x,'y':y}, {'a':a,'b':b}
你可以写:
from var_arguments import recon_dict, use_dargs
def f(d1,d2):
r=f2(dargs=[d1,d2])
return recon_dict(d1,r), recon_dict(d2,r)
@use_dargs
def f2(x,y,a,b):
y=x+a
return locals()
我写了这样的解决方案来匹配你的目标:字典到达和分组,我们最小化我们在字典中提到键名称和/或手动访问它们的次数。具体来说,我们只需要这样就提到x,y,a和b。
它的工作原理基本上是@use_dargs修改f2以便它接受一个可选的dargs关键字参数,如果存在,它应该提供一个字典列表(dargs = [d1,d2])。关键/价值 这些词典中的对被添加到关键字参数中,否则这些参数将提供给函数的调用,关键字参数具有最高优先级,d2具有第二高,并且 d1具有最低优先级。因此,您可以通过各种方式调用f2并获得相同的结果:
f2(1,2,3,4)
f2(1,a=3,dargs=[dict(y=2,b=4)])
f2(dargs=[dict(x=1,y=2),dict(a=3,b=4)])
recon_dict适用于您拥有一个包含旧值的字典的情况 对于您感兴趣的所有密钥,以及另一个拥有该密钥的字典 所有这些键的新值(以及您可能不想要的其他键)。例如:
old_d=dict(a=8,b=9) # I want these keys, but they're old values
xyab=dict(x=1,y=2,a=3,b=4) # These are the new values, but I don't want all of them
new_d=recon_dict(old_d,xyab)
assert new_d==dict(a=3,b=4)
以下是一些额外的技巧,可以在var_arguments处理的函数体中多次删除提及变量名称的冗余。 首先,我们可以改变:
{'x':x,'y':y}
成:
ddict('x,y',locals())
同样,我们可以改变:
f(x=x,y=y)
成:
dcall(f,'x,y',locals())
更一般地说,如果我们有一个带有键x和y的字典xy,如果我们的局部变量包含a和b,我们可以改变:
f(x=xy['x'],y=xy['y'],a=a,b=b)
成:
ldcall(f,'x,y,a,b',[locals(),xy])
答案 10 :(得分:0)
您可以使用sorcery:
from sorcery import unpack_dict
x, y = unpack_dict(d1)