我们来看一下@karlknechtel的优秀代码并了解其作用:
>>> d = dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
但是它是如何工作的?
要构建一个字典,可以使用
dict()
函数。它需要一个元组列表作为参数。在3.x和>2.7中,您还可以使用字典理解(请参见@nightcracker的答案)。
让我们分析一下字典的参数。首先,我们需要m中所有项的列表。每个项都是格式为(key, value)的元组。
>>> d.items()
[('group_id', 3), ('user_id', 1), ('user', 'user1'), ('group_name', 'ordinary users')]
给定一个键值k
,我们可以通过m[k]
获取字典m
中对应的值。
>>> k = 'user_id'
>>> m[k]
'uid'
很遗憾,d
中并非所有的键值也存在于 m
中。
>>> k = 'user'
>>> m[k]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'user'
为了解决这个问题,你可以使用
d.get(x, y)
,如果键
x
存在,则返回
d[x]
,否则返回默认值
y
。现在,如果来自
d
的键
k
在
m
中不存在,我们只需保留它,所以默认值是
k
。
>>> m.get(k, k).
'user'
现在我们准备构建一个元组列表以供
dict()
使用。为了在一行代码中构建列表,我们可以使用
列表推导式。
要构建一个平方数列表,您可以编写如下代码:
>>> [x**2 for x in range(5)]
[0, 1, 4, 9, 16]
在我们的情况下,它看起来像这样:
>>> [(m.get(k, k), v) for (k, v) in d.items()]
[('gid', 3), ('uid', 1), ('user', 'user1'), ('group', 'ordinary users')]
这句话有点绕,让我们再看一遍。
给我一个列表 [...]
,其中包含元组:
[(.., ..) ...]
我希望对于d
中的每个元素x
,都能得到一个元组:
[(.., ..) for x in d.items()]
我们知道每个项都是一个包含两个元素的元组,因此我们可以将其扩展为两个变量
k
和
v
。
[(.., ..) for (k, v) in d.items()]
每个元组应该以m中正确的键作为第一个组成部分,或者如果k不存在于m中,则以k作为第一个组成部分,并且以d作为值。
[(m.get(k, k), v) for (k, v) in d.items()]
我们可以将它作为参数传递给
dict()
函数。
>>> dict([(m.get(k, k), v) for (k, v) in d.items()])
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
很好!但是你可能会说,@karlknechtel没有使用方括号。
没错,他没有使用列表推导式,而是使用了生成器表达式。简单来说,它们的区别在于列表推导式将整个列表都建立在内存中,而生成器表达式一次只计算一个项目。如果列表仅作为中间结果,使用生成器表达式通常是个不错的选择。在这个例子中,两种方式并没有区别,但养成使用生成器表达式的好习惯总是明智的。
等价的生成器表达式如下所示:
>>> ((m.get(k, k), v) for (k, v) in d.items())
<generator object <genexpr> at 0x1004b61e0>
如果你将一个生成器表达式作为函数参数传递,通常可以省略外层的括号。最终我们得到:
如果您将生成器表达式作为函数参数传递,通常可以省略外部括号。最终结果如下:
>>> dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
一行代码中发生了很多事情。有些人说这种写法难以阅读,但是一旦你习惯了,将这段代码拆成几行反而会变得难以阅读。只要不过度使用就可以了。列表推导式和生成器表达式非常强大,但是伴随着强大的能力也有伟大的责任。对于这个好问题给予+1!