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

Pau*_*jan 119 python language-features dictionary language-design

我想做:

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
Run Code Online (Sandbox Code Playgroud)

但是如果觉得这个功能真的很麻烦,我宁愿做到:

        return self.add_award({
            "name" : name,
            "description" : desc_string % count,
            "points" : points,
            "parent_award" : parent,
        }.update(award_dict), siteAlias, alias).award
Run Code Online (Sandbox Code Playgroud)

为什么不更新返回对象以便链接?

JQuery这样做是为了链接.为什么python不接受它?

Ale*_*lli 193

Python主要实现了一种实用的命令查询分离方式:mutators返回None(使用实际引发的异常,如pop;-),因此它们不可能与访问器混淆(同样,赋值不是表达式,声明 - 表达分离是存在的,等等).

这并不意味着当你真正想要的时候没有很多方法可以合并,例如,dict(a, **award_dict)制作一个新的dict,就像你希望.update返回的那个- 所以为什么不使用那个如果你真的觉得它很重要?

编辑:顺便说一下,在你的具体情况下,不需要a一路创建:

dict(name=name, description=desc % count, points=points, parent_award=parent,
     **award_dict)
Run Code Online (Sandbox Code Playgroud)

创建一个与你的语义完全相同的单个dict a.update(award_dict)(包括,如果发生冲突,则award_dict覆盖你明确给出的条目;获得其他语义,即有明确的条目"赢得"这样的冲突,award_dict作为唯一的位置 arg,关键字之前传递,并且丧失**形式 - dict(award_dict, name=name等等).

  • `dict(a,**award_dict)`只是摇滚,正是我想要的 - 谢谢你!(之前使用`dict(d1.items()+ d2.items())` (20认同)
  • 此外,如果 Award_dict 中的键不是字符串,解释器将抛出 `TypeError` (4认同)
  • `dict(old_dict, old_key=new_value)` 不会为关键字抛出多个值并返回新的 dict。 (4认同)
  • 原始解决方案并不健壮。如果 Award_dict 包含已指定的键,则将为重复的关键字参数抛出 SyntaxError 。jamylak 的解决方案 dict(itertools.chain(d1.iteritems(), .. d<n>.iteritems())) 不仅适用于字典具有重复键的情况,而且还可以轻松地允许您稍后将多个字典与 dicts 合并链优先于最终值。 (3认同)

Mar*_*wis 35

按照惯例,Python的API区分了过程和函数.函数从其参数(包括任何目标对象)中计算新值; 过程修改对象并且不返回任何内容(即它们返回None).所以程序有副作用,功能没有.update是一个过程,因此它不返回值.

这样做的动机是否则会产生不良副作用.考虑

bar = foo.reverse()
Run Code Online (Sandbox Code Playgroud)

如果反向(就地反转列表)也会返回列表,用户可能会认为反向返回一个新的列表,该列表被分配给bar,并且从不会注意到foo也被修改.通过反向返回None,他们立即意识到bar不是反转的结果,并且看起来更接近反向的效果.

  • 我认为原因是明确的.在`bar = foo.reverse()`中,你可以认为`foo`没有被修改.为了避免混淆,你有`foo.reverse()`和`bar = reversed(foo)`. (3认同)

Cri*_*ton 15

>>> dict_merge = lambda a,b: a.update(b) or a
>>> dict_merge({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}
Run Code Online (Sandbox Code Playgroud)

请注意,除了返回合并的dict之外,它还会就地修改第一个参数.所以dict_merge(a,b)会修改一个.

或者,当然,你可以全部内联:

>>> (lambda a,b: a.update(b) or a)({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}
Run Code Online (Sandbox Code Playgroud)

  • -1`lambda`不应该像那样使用,而是使用传统的函数`def`代替 (10认同)
  • 甚至不需要lambda,只需使用`a.update(b)或a` (6认同)

小智 11

这很容易,因为:

(lambda d: d.update(dict2) or d)(d1)
Run Code Online (Sandbox Code Playgroud)


小智 8

没有足够的评论声誉留在最佳答案

@beardc这似乎不是CPython的事情.PyPy给我"TypeError:关键字必须是字符串"

该解决方案**kwargs仅起作用,因为要合并的字典只有字符串类型的键.

>>> dict({1:2}, **{3:4})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
Run Code Online (Sandbox Code Playgroud)

VS

>>> dict({1:2}, **{'3':4})
{1: 2, '3': 4}
Run Code Online (Sandbox Code Playgroud)


Est*_*ber 5

它不是不可接受的,而是那种dicts没有实现的方式.

如果你看看Django的ORM,它会广泛使用链接.它并不气馁,你甚至可以继承dict并只覆盖update更新return self,如果你真的想要它.

class myDict(dict):
    def update(self, *args):
        dict.update(self, *args)
        return self
Run Code Online (Sandbox Code Playgroud)