为什么python dict.update()不返回对象?

201 投票
12 回答
99572 浏览
提问于 2025-04-15 14:28

我有这段代码:

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 个回答

35

这很简单,像这样:

(lambda d: d.update(dict2) or d)(d1)

或者,如果你不想修改字典的话:

(lambda d: d.update(dict2) or d)(d1.copy())
47

在Python中,API有个约定,就是把“过程”和“函数”区分开来。函数是用来计算新值的,它会根据输入的参数(包括任何目标对象)来返回一个新值;而过程则是用来修改对象的,它不会返回任何东西(也就是说,它返回的是None)。所以,过程会有副作用,而函数则没有。比如,update就是一个过程,所以它不会返回值。

这样做的原因是,如果不这样区分,可能会出现一些不想要的副作用。举个例子:

bar = foo.reverse()

如果reverse(这个函数是用来就地反转列表的)也返回反转后的列表,用户可能会误以为reverse返回的是一个新列表,并把它赋值给bar,而不会注意到foo也被修改了。通过让reverse返回None,用户就会立刻明白bar并不是反转的结果,这样他们就会更仔细地去看reverse的实际效果。

280

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 等等)。

撰写回答