Python: 在索引赋值中使用for循环
在阅读托比·塞加兰的《编程集体智能》这本很棒的书时,我遇到了一些关于索引赋值的技巧,我不是很熟悉。
比如说这个:
createkey='_'.join(sorted([str(wi) for wi in wordids]))
或者:
normalizedscores = dict([(u,float(l)/maxscore) for (u,l) in linkscores.items()])
这些嵌套的元组让我有点困惑。其实这些变量被赋值的是什么呢?我当然知道 .join
的结果是一个字符串,但后面的那个呢?如果有人能解释一下这些循环的原理,我会非常感激。我觉得这些技巧应该是比较常见的,但作为一个Python新手,问这个问题可能有点不好意思。谢谢!
6 个回答
1
后者等同于:
normalizedscores = {}
for u, l in linkscores.items():
normalizedscores[u] = float(l) / maxscore
3
我们先来看第一个:
str(wi) for wi in wordids
是把wordids
里的每一个元素都转成字符串。sorted(...)
是把这些字符串按字母顺序排列。'_'.join(...)
是把排好序的字符串用下划线连接成一个长字符串。
现在来看第二个:
normalizedscores = dict([(u,float(1)/maxscore) for (u,l) in linkscores.items()])
linkscores
是一个字典(或者说类似字典的东西)。for (u,l) in linkscores.items()
是在遍历字典里的每一项,把每一项的键和值分别赋给u
和l
。(u,float(1)/maxscore)
是一个元组,第一个元素是u
,第二个元素是1/maxscore
(我觉得这里可能有个小错误:用float(l)/maxscore
会更合理——注意这里的字母是小写的 l,而不是数字一)。dict(...)
是从这些元组里创建一个新的字典,元组的第一个元素作为键,第二个元素作为值。
简单来说,这段代码是复制了这个字典,保留了键,并把每个值都除以 maxscore
。
15
[str(wi) for wi in wordids]
这是一个列表推导式。
a = [str(wi) for wi in wordids]
这和下面的内容是一样的
a = []
for wi in wordids:
a.append(str(wi))
所以
createkey='_'.join(sorted([str(wi) for wi in wordids]))
这个代码从wordids
中的每个项目创建一个字符串列表,然后对这个列表进行排序,并用_
作为分隔符把它们连接成一个大字符串。
正如agf正确指出的,你也可以使用生成器表达式,它看起来和列表推导式很像,只不过用的是圆括号而不是方括号。如果你后面不需要这个列表(除了遍历它),这样做可以避免创建一个列表。而且如果你已经有了圆括号,比如在sorted(...)
的情况下,你可以直接去掉方括号。
不过,在这个特殊情况下,你不会获得性能上的好处(实际上,它会慢大约10%;我测过了),因为sorted()
无论如何都需要构建一个列表,但这样看起来会更好一些:
createkey='_'.join(sorted(str(wi) for wi in wordids))
normalizedscores = dict([(u,float(l)/maxscore) for (u,l) in linkscores.items()])
这个代码遍历字典linkscores
中的每个项目,每个项目都是一个键/值对。它创建一个键和l/maxscore
的元组列表,然后把这个列表再转回字典。
不过,从Python 2.7开始,你也可以使用字典推导式:
normalizedscores = {u:float(l)/maxscore for (u,l) in linkscores.items()}
这里有一些时间数据:
Python 3.2.2
>>> import timeit
>>> timeit.timeit(stmt="a = '_'.join(sorted([str(x) for x in n]))", setup="import random; n = [random.randint(0,1000) for i in range(100)]")
61.37724242267409
>>> timeit.timeit(stmt="a = '_'.join(sorted(str(x) for x in n))", setup="import random; n = [random.randint(0,1000) for i in range(100)]")
66.01814811313774
Python 2.7.2
>>> import timeit
>>> timeit.timeit(stmt="a = '_'.join(sorted([str(x) for x in n]))", setup="import random; n = [random.randint(0,1000) for i in range(100)]")
58.01728623923137
>>> timeit.timeit(stmt="a = '_'.join(sorted(str(x) for x in n))", setup="import random; n = [random.randint(0,1000) for i in range(100)]")
60.58927580777687