为什么python dict.update()不返回对象?
我有这段代码:
award_dict = {
"url": "http://facebook.com",
"imageurl": "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png",
"count": 1,
}
def award(name, count, points, desc_string, my_size, parent):
if my_size > count:
a = {
"name": name,
"description": desc_string % count,
"points": points,
"parent_award": parent,
}
a.update(award_dict)
return self.add_award(a, siteAlias, alias).award
不过这段代码感觉有点繁琐。我更希望能够这样写:
def award(name, count, points, desc_string, my_size, parent):
if my_size > count:
return self.add_award({
"name": name,
"description": desc_string % count,
"points": points,
"parent_award": parent,
}.update(award_dict), siteAlias, alias).award
为什么这个 update
方法不返回原来的字典,这样就可以像在JQuery中那样进行 链式调用?在Python中为什么不可以这样做呢?
可以查看 如何在Python中用单个表达式合并两个字典? 来了解一些解决方法。
12 个回答
这很简单,像这样:
(lambda d: d.update(dict2) or d)(d1)
或者,如果你不想修改字典的话:
(lambda d: d.update(dict2) or d)(d1.copy())
在Python中,API有个约定,就是把“过程”和“函数”区分开来。函数是用来计算新值的,它会根据输入的参数(包括任何目标对象)来返回一个新值;而过程则是用来修改对象的,它不会返回任何东西(也就是说,它返回的是None)。所以,过程会有副作用,而函数则没有。比如,update就是一个过程,所以它不会返回值。
这样做的原因是,如果不这样区分,可能会出现一些不想要的副作用。举个例子:
bar = foo.reverse()
如果reverse(这个函数是用来就地反转列表的)也返回反转后的列表,用户可能会误以为reverse返回的是一个新列表,并把它赋值给bar,而不会注意到foo也被修改了。通过让reverse返回None,用户就会立刻明白bar并不是反转的结果,这样他们就会更仔细地去看reverse的实际效果。
Python 在实现上主要采用了一种带有实用主义色彩的“命令查询分离”方式:修改数据的操作(我们称为“变更器”)返回 None
(当然也有一些例外,比如 pop
;-)这样就不会和获取数据的操作(我们称为“访问器”)混淆。而且,赋值操作本身不是一个表达式,这种语句和表达式的分离也是存在的。
不过,这并不意味着你不能在需要的时候把这些操作混合在一起。例如,dict(a, **award_dict)
会创建一个新的字典,这个字典的样子和你希望 .update
返回的结果很像——所以如果你觉得这样做很重要,为什么不直接使用这个呢?
补充说明:顺便说一下,在你的具体情况下,其实不需要在过程中创建 a
:
dict(name=name, description=desc % count, points=points, parent_award=parent,
**award_dict)
这个方法创建了一个字典,它的语义和你的 a.update(award_dict)
完全一样(包括在冲突的情况下,award_dict
中的条目会覆盖你明确给出的条目;如果你想要另一种语义,也就是让明确给出的条目在冲突中“胜出”,只需将 award_dict
作为唯一的“位置”参数放在前面,而不是用 **
的形式,比如 dict(award_dict, name=name
等等)。