Python中用列表初始化set时是否保证按输入顺序保留首个唯一元素?
问题解答
规则判定
Python 3.7及以上的官方语言规范已经明确,set初始化时会严格按照输入可迭代对象的顺序逐个处理元素:
- 当遇到重复元素(即满足
__hash__返回值相等且__eq__返回True)时,会保留第一个出现的实例,直接丢弃后续出现的重复元素,不会发生覆盖。 - 3.6版本的CPython已经把这个逻辑作为实现细节支持,3.7正式纳入语言规范,所有符合规范的Python实现都要遵守该规则。
- 3.6以下版本的Python没有该保证,结果不可预期。
针对你给出的示例:
class Class(): def __eq__(self, other): return True def __hash__(self): return 1 a = Class() b = Class() # a == b -> True a.property = "a" b.property = "b" l = list(set([a, 2, b])) print(l[0].property) l = list(set([b, 2, a])) print(l[0].property)
在3.7+版本下运行,第一次print保证输出a,第二次print保证输出b,完全符合你的预期。
实现逻辑查看
你可以在CPython源码的Objects/setobject.c文件中查看set_init函数的实现:set初始化时会遍历传入的可迭代对象,逐个调用set_add_key接口添加元素,添加逻辑中如果检测到当前元素已经存在于集合中,会直接跳过本次添加操作,不会修改已存在的元素实例,因此首个加入的实例会被保留。
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

