您调用.setdefault()
的值为:v
newlist.setdefault(v,[])
并且v
必须已经定义并设置为'go'
. 如果您在新的解释器中运行此代码,或者del v
先执行此代码,Python 会引发NameError
异常:
>>> newlist = {}
>>> newlist.setdefault(v,[]).append((v,k) for k,v in dicnew.items() if v==value)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'v' is not defined
>>> v = 'go'
>>> newlist.setdefault(v, [])
[]
>>> newlist
{'go': []}
该setdefault()
部分在.append()
方法执行之前执行。方法v
内部生成器表达式中使用的名称与调用中使用的名称无关。.append()
v
.setdefault()
在 Python 2.7 及更早版本中,列表理解变量“泄漏”到父作用域:
>>> [foo for foo in range(3)]
[0, 1, 2]
>>> foo
2
因此,v
在您之前的循环中设置,并且分配给它的最后一个值是'go'
.
如果您想通过收集每个值的键列表来“反转”字典,请使用:
from collections import defaultdict
keys_for_value = defaultdict(list)
for key, value in original_dict.iteritems():
keys_for_value[value].append(key)
如果您必须坚持使用单线,请使用itertools.groupby
和排序:
from itertools import groupby
from operator import itemgetter
v = itemgetter(1)
keys_for_value = {value: [k for k, v in items] for value, items in groupby(sorted(original_dict.iteritems(), key=v, key=v)}
这会更慢,因为您需要先对字典项进行排序(成本 O(n log n)),然后再循环排序结果(本身 O(n),所以总共 O(n) + O(n log n)),而不是使用简单的 O(n) 复杂度defaultdict
和for
循环。