嗯,很绕的标题,但是这是为了解决这样一个问题:存在一个python列表,这个列表是由一系列的同样类型的字典组成,想要对该列表中的每一个字典进行更新(按照一定规则),并返回一个新的列表。
如此假定:
In [1]: d = [ # 原始列表
...: {"id":1,"name":"test1"},
...: {"id":2,"name":"test2"}
...: ]
In [2]: new_d = [ # 想要实现的效果,其中new_id的值为id值加1,并保留原字典中所有(未被更新)的项
...: {"id":1,"name":"test1","new_id":2},
...: {"id":2,"name":"test2","new_id":3}
...: ]
使用最简单的方法就是,新建一个空列表,使用for循环遍历已有的字典列表,并对每个字典进行更新后添加进新建的空列表中。如下代码示意
In [3]: d_1 = []
...: for i in d:
...: i.update({"new_id": i["id"] + 1})
...: d_1.append(i)
...: d_1
...:
Out[3]:
[{'id': 1, 'name': 'test1', 'new_id': 2},
{'id': 2, 'name': 'test2', 'new_id': 3}]
那有没有其他的方法馁,这就是本篇文章探讨了。。(最近奇技淫巧想多了。
就想用列表推导式来解决(毕竟如In[3] 的结构很容易改写成列表推导式)
In [4]: [i.update({"new_id": i["id"] + 1}) for i in d]
Out[4]: [None, None]
然而却得到了这样的结果?为什么馁。
查看官方文档dict.update
update([other])
Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.
update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary is then updated with those key/value pairs: d.update(red=1, blue=2).
好吧,dict.update返回的是None。那换个思路(对,上stackoverflow找找。
然后就看到了这篇python - update dict in list comprehension - Stack Overflow
来,我们来尝试下
In [5]: [{i:j for i,j in t.items() + [("new_id",t["id"]+1)]} for t in d]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-920aa73acbd6> in <module>()
----> 1 [{i:j for i,j in t.items() + [("new_id",t["id"]+1)]} for t in d]
<ipython-input-5-920aa73acbd6> in <listcomp>(.0)
----> 1 [{i:j for i,j in t.items() + [("new_id",t["id"]+1)]} for t in d]
TypeError: unsupported operand type(s) for +: 'dict_items' and 'list'
什么鬼嘛(摔 ,怪不得是0赞0踩的答案。直接抛出了TypeError。
原来,在python3中,dict.items()不像py2中一样返回一个列表,而是返回了一个dict_items对象。(参见2.7#dict.items 以及 3.6#dict.items)
items()
Python2.7 : Return a copy of the dictionary’s list of (key, value) pairs.
Python3.6 : Return a new view of the dictionary’s items ((key, value) pairs).
这都不行,那也不行,那lambda。。 也不行。。。就在我想要放弃的时候
我神tm的想出了一个方法。
你update不是不返回吗,但是实际上字典列表中的字典已经更新了,那用or来过滤掉就行。就有了以下的列表推导式。
在执行的过程中因为 None or i => i
让推导式中生成值为i。
In [6]: [i.update({"new_id": i["id"] + 1}) or i for i in d]
Out[6]:
[{'id': 1, 'name': 'test1', 'new_id': 2},
{'id': 2, 'name': 'test2', 'new_id': 3}]
那个SO的答案也不算错吧,dict_items对象转为list不就好了嘛
[{i:j for i,j in list(t.items()) + [("new_id",t["id"]+1)]} for t in d]
嗯,也对。
刚开始接触Python的时候什么都不懂,就只能想这种吃力不讨好的解决方法。
现在想想这种东西其实还是用list(map(function, list))来做更好些233333
比如按照我这文所设的话应该是 list(map(lambda d:d["new_id"] = d["id"] + 1), l)