Python中的set是一种无序且不重复的集合数据类型,在Python 3.7版本前后,set对于插入顺序的支持存在明显差异,这种差异源于底层数据结构的调整。

Python 3.7之前set的行为
在Python 3.7之前的版本中,set的底层实现基于哈希表,但没有对插入顺序做额外维护,因此set的元素输出顺序和插入顺序没有关联,每次遍历set得到的顺序都可能不同,尤其是在哈希表发生扩容之后,元素顺序变化会更明显。
我们可以通过以下代码验证Python 3.6及更早版本的行为:
# Python 3.6及之前版本运行示例 my_set = set() my_set.add(1) my_set.add(2) my_set.add(3) my_set.add(4) # 输出顺序不一定是1,2,3,4,可能是其他顺序 print(my_set)
Python 3.7及之后set的行为
Python 3.7版本开始,官方对set的底层实现做了优化,在哈希表的基础上额外维护了插入顺序的链表结构,因此set默认会保持元素的插入顺序,遍历set时输出的顺序和元素插入的顺序一致。
对应的验证代码如下:
# Python 3.7及之后版本运行示例 my_set = set() my_set.add(1) my_set.add(2) my_set.add(3) my_set.add(4) # 输出顺序固定为1,2,3,4,和插入顺序一致 print(my_set)
底层实现原理差异
Python 3.7之前,set的哈希表只存储元素的哈希值和对应的元素引用,没有记录元素的插入先后顺序,因此遍历时按照哈希表的存储位置输出,顺序不可控。
Python 3.7之后,set的哈希表每个条目除了存储哈希值、元素引用之外,还增加了前向和后向指针,这些指针组成了一个双向链表,用来记录元素的插入顺序,遍历set时按照链表的顺序依次输出元素,因此就能保持插入顺序。
需要注意的是,这个特性在Python 3.7中属于实现细节,到Python 3.8版本才正式成为语言规范的一部分,不过实际使用中从3.7开始就可以稳定依赖这个特性。
Python 3.7之前版本保持插入顺序的替代方案
如果需要在Python 3.7之前的版本中实现类似有序set的功能,可以使用collections.OrderedDict来模拟,OrderedDict本身会保持键的插入顺序,我们只需要把set的元素作为OrderedDict的键,值设为None即可。
实现代码如下:
from collections import OrderedDict
class OrderedSet:
def __init__(self, iterable=None):
self._dict = OrderedDict()
if iterable:
for item in iterable:
self._dict[item] = None
def add(self, item):
self._dict[item] = None
def __iter__(self):
return iter(self._dict.keys())
def __len__(self):
return len(self._dict)
def __repr__(self):
return f"OrderedSet({list(self._dict.keys())})"
# 使用示例
ordered_set = OrderedSet()
ordered_set.add(1)
ordered_set.add(2)
ordered_set.add(3)
print(ordered_set) # 输出OrderedSet([1, 2, 3]),顺序和插入一致
不同场景下的选择建议
- 如果使用Python 3.7及更高版本,直接使用原生set即可,无需额外处理,原生set的性能也更好。
- 如果需要兼容Python 3.7之前的版本,优先考虑使用上述OrderedSet的实现,或者根据需求判断是否真的需要保持插入顺序,因为旧版本原生set的无序性也可以满足大部分去重需求。
- 如果需要频繁进行顺序相关的操作,比如获取第一个插入的元素,有序set的实现会更合适。
Pythonset插入顺序Python_3.7有序集合修改时间:2026-06-28 10:03:25