Python使用setitem与map实现列表去重的脚本异常问题咨询
可正常运行的修复后代码
from operator import setitem def distinct(l): d = {} # 两处修改:1. 用list()消费map惰性迭代器触发执行 2. 补全值的可迭代对象长度和输入列表匹配 list(map(setitem, (d,)*len(l), l, [None]*len(l))) return list(d.keys()) # 测试调用 li = [1, 5, 6, 1, 8] x = distinct(li) print(x) # 输出(Python3.7+字典保留插入顺序):[1, 5, 6, 8]
原代码运行失败的核心原因
- Python3中
map()返回惰性迭代器,只有迭代它的时候才会执行内部逻辑,原代码没有消费map()的返回值,setitem从未被调用,字典始终为空。 - 原代码中
map()的第三个可迭代参数是空列表[],map()的迭代次数等于所有传入可迭代对象的最小长度,这里长度为0,就算消费了map()也不会执行任何操作,属于明显的笔误。
逻辑细节解释
1. operator.setitem作用
setitem是operator模块封装的语法糖,完全等效于Python赋值语句obj[key] = value,固定接收三个参数:要操作的对象、键、要赋的值。
2. (d,)*len(l)的作用
这行代码会生成一个和输入列表长度相同的元组,元组内所有元素都是同一个字典d的引用。例如输入列表长度为5时,生成的元组为(d, d, d, d, d),目的是让每次setitem调用都操作同一个字典,利用字典键的唯一性完成去重。
3. map()与setitem的协同逻辑
map()会按位置依次从后续传入的所有可迭代对象中取元素,逐个传给第一个参数的函数,直到最短的可迭代对象耗尽:
- 从第一个可迭代对象
(d,)*len(l)取字典d,传给setitem的第一个参数 - 从第二个可迭代对象输入列表
l取元素,传给setitem的第二个参数作为键 - 从第三个可迭代对象
[None]*len(l)取None,传给setitem的第三个参数作为值
每次迭代都会执行一次d[当前元素] = None,重复元素会自动覆盖,最终字典的键就是去重后的结果。
内容的提问来源于stack exchange,提问作者John D
相关产品推荐
相关产品推荐

