如何处理带可调用对象的python字典?
我想创建一个Python字典,这个字典里的值需要单独进行计算。
比如,在下面这个不工作的例子中,我定义了
a = {'key1': 'value1', 'key2': 42, 'key3': foo(20)}
例如,
def foo(max):
"""Returns random float between 0 and max."""
return max*random.random()
处理完这个字典后,我想得到
a_processes = {'key1': 'value1', 'key2': 42, 'key3': 12.238746374}
这个例子不工作是因为,键key3
的值会立即被计算,而foo(20)
并不是一个可以调用的东西。要让它工作,可以使用类似于
a = {'key1': 'value1', 'key2': 42, 'key3': foo}
但这样的话,foo
就会缺少它的参数。处理这个问题的一种方法是这样定义字典
a = {'key1': 'value1', 'key2': 42, 'key3': [foo, 20]}
然后用以下的处理方式
a_processed = dict([k,process(v)] for k,v in a.items())
在这个处理方式中,process
是一个有意义的函数,它会检查传入的参数是否是一个列表,或者第一个元素是否是一个可以调用的函数,并用剩下的参数来调用它。
我想问的是,有没有更好的方法或想法来实现我的基本想法?
2 个回答
9
使用 functools.partial()
可以创建一个可调用的对象,这个对象会把一组参数应用到另一个可调用的对象上:
from functools import partial
a = {'key1': 'value1', 'key2': 42, 'key3': partial(foo, 20)}
现在,key3
的值是一个可调用对象;当你执行 a['key3']()
时,它会调用 foo(20)
并返回结果。
你仍然需要“处理”这个字典(可以用 callable()
函数来测试):
{k: v() if callable(v) else v for k, v in a.iteritems()}
当然。如果你使用的是 Python 3,记得用 a.items()
来代替。
使用 functools.partial
的设置可以让你根据需要添加额外的参数(前提是 foo()
支持这些参数):
a['key3']('additional', arguments='accepted')
你甚至可以创建一个字典的子类,当访问某个键时,它会自动执行这个操作:
def CallablesDict(dict):
def __getitem__(self, key):
value = super(CallablesDict, self).__getitem__(key)
return value() if callable(value) else value
然后定义 a
为:
a = CallablesDict({'key1': 'value1', 'key2': 42, 'key3': partial(foo, 20)})
print a['key3'] # calls foo(20)
6
我经常在这里使用一个不带参数的lambda
,只是因为我喜欢这种写法:
>>> def foo(x):
... return x*100
...
>>> a = {'key1': 'value1', 'key2': 42, 'key3': lambda: foo(20)}
>>> a
{'key3': <function <lambda> at 0x96ae80c>, 'key2': 42, 'key1': 'value1'}
>>> {k: v() if callable(v) else v for k,v in a.iteritems()}
{'key3': 2000, 'key2': 42, 'key1': 'value1'}