Python字典dict特点与集合set有序性说明

0 阅读5分钟

Python字典dict特点与集合set有序性说明


一、dict(字典)的特点

1. 键值对存储

字典存的是 key-value(键值对),通过键来查找值。

person = {"name": "小明", "age": 25, "city": "北京"}
print(person["name"])   # 小明

2. 键必须唯一,值可以重复

d = {"a": 1, "b": 2, "a": 3}   # 键 a 重复,后面的覆盖前面的
print(d)                        # {'a': 3, 'b': 2}

值可以重复:

d = {"a": 1, "b": 1, "c": 1}   # 合法,值都是 1

3. 键必须可哈希(不可变),值任意

可以作为键的:字符串、数字、元组、布尔值、None。 不能作为键的:列表、字典、集合(因为它们是可变的)。

d = {}
d["name"] = "小明"       # ✅ 字符串作键
d[1] = "one"             # ✅ 数字作键
d[(1, 2)] = "元组作键"    # ✅ 元组作键
d[[1, 2]] = "列表作键"    # ❌ TypeError: unhashable type: 'list'

4. 查找效率 O(1)

底层是哈希表,按键查找的平均时间复杂度是 O(1)。

d = {"a": 1, "b": 2}
print(d["a"])   # 瞬间找到,不管字典多大

5. 有序(Python 3.7+)

从 Python 3.7 开始,字典保证按插入顺序遍历。

d = {"b": 2, "a": 1, "c": 3}
print(list(d.keys()))   # ['b', 'a', 'c'],按插入顺序

在 Python 3.6 及更早版本,字典是无序的。如果面试被问到,要说清楚版本。

6. 可变

可以随时增删改:

d = {"a": 1}
d["b"] = 2      # 增
d["a"] = 10     # 改
del d["b"]      # 删

7. 常用操作

d = {"name": "小明", "age": 25}

# 查
d["name"]              # 小明,键不存在会 KeyError
d.get("gender")        # None,键不存在返回 None
d.get("gender", "未知") # "未知",指定默认值

# 增/改
d["city"] = "北京"      # 键不存在则增,存在则改

# 删
del d["age"]           # 删除键,不存在会 KeyError
d.pop("age", None)     # 安全删除,不存在返回默认值
d.clear()              # 清空

# 遍历
for key in d:                    # 遍历键
    ...
for key, value in d.items():     # 遍历键值对
    ...
for value in d.values():         # 遍历值
    ...

# 成员判断(判断键)
if "name" in d:
    ...

8. 字典推导式

squares = {x: x**2 for x in range(5)}
print(squares)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

二、set(集合)的特点

1. 无序、不重复

集合是一组唯一的、无序的元素。

s = {1, 2, 3, 2, 1}
print(s)   # {1, 2, 3},自动去重

2. 元素必须可哈希

和字典的键一样,集合元素必须是不可变类型。

s = {1, 2, "hello", (1, 2)}    # ✅
s = {[1, 2]}                    # ❌ TypeError: unhashable type: 'list'

3. 无序

集合不保证顺序,遍历顺序是不确定的。

s = {3, 1, 2}
print(s)   # 可能是 {1, 2, 3},也可能是 {3, 1, 2},取决于哈希值

注意:集合不是“有序”的。虽然打印出来看起来有顺序,但那是哈希表的内部排列,不是你插入的顺序。不同版本、不同运行环境可能不一样。

4. 查找效率 O(1)

底层也是哈希表,判断元素是否存在非常快。

s = {1, 2, 3, 4, 5}
print(3 in s)    # True,O(1)

5. 可变(但元素不可变)

集合本身可以增删元素:

s = {1, 2, 3}
s.add(4)         # 增
s.remove(1)      # 删,不存在会 KeyError
s.discard(10)    # 删,不存在不报错
s.pop()          # 随机删一个
s.clear()        # 清空

但元素本身不能是可变类型。

6. 常用操作

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# 并集
a | b              # {1, 2, 3, 4, 5, 6}
a.union(b)         # 同上

# 交集
a & b              # {3, 4}
a.intersection(b)  # 同上

# 差集(在 a 不在 b)
a - b              # {1, 2}
a.difference(b)    # 同上

# 对称差集(只在其中一个)
a ^ b              # {1, 2, 5, 6}
a.symmetric_difference(b)

# 子集/超集
{1, 2} <= a        # True,子集
a >= {1, 2}        # True,超集

7. 集合推导式

squares = {x**2 for x in range(5)}
print(squares)   # {0, 1, 4, 9, 16}

8. 创建集合

s = {1, 2, 3}          # 字面量
s = set()              # 空集合,注意不是 {}(那是空字典)
s = set([1, 2, 2, 3])  # 从列表创建,自动去重 -> {1, 2, 3}
s = set("hello")       # 从字符串创建 -> {'h', 'e', 'l', 'o'}

经典坑{} 是空字典,不是空集合。

print(type({}))     # <class 'dict'>
print(type(set()))  # <class 'set'>

三、dictset 对比

对比项dictset
存储内容键值对单个元素
是否可重复键唯一,值可重复元素唯一
是否有序有序(3.7+,按插入顺序)无序
底层结构哈希表哈希表
查找效率O(1)O(1)
元素要求键必须可哈希元素必须可哈希
可变性可变可变
空对象写法{}set()
典型用途关联数据、映射去重、成员判断、集合运算

四、回答你的两个具体问题

问题 1:dict 有什么特点?

总结成 7 点:

  1. 键值对存储,按键查找 O(1)。
  2. 键唯一,值可重复。
  3. 键必须可哈希(不可变),值任意。
  4. 有序(Python 3.7+,按插入顺序)。
  5. 可变,可增删改。
  6. 支持多种遍历方式(keys、values、items)。
  7. 支持字典推导式。

问题 2:set 是不能有重复值,有序吗?

不能有重复值:✅ 正确,集合元素唯一。

有序吗:❌ 无序。集合不保证顺序,遍历顺序由哈希值决定,和你插入的顺序无关。

s = {5, 1, 3, 2, 4}
print(s)   # 可能是 {1, 2, 3, 4, 5},也可能是别的顺序

如果你需要既去重又保持顺序,不能用 set,要用 dict.fromkeys()

items = [3, 1, 2, 3, 1, 4]
unique_ordered = list(dict.fromkeys(items))
print(unique_ordered)   # [3, 1, 2, 4],去重且保持原顺序

这是 Python 3.7+ 的常用技巧,因为字典有序,dict.fromkeys() 会按插入顺序去重。


五、一句话总结

问题答案
dict 特点?键值对、键唯一、键可哈希、有序(3.7+)、O(1) 查找、可变
set 能重复吗?不能,元素唯一
set 有序吗?无序,遍历顺序不确定
想有序去重?dict.fromkeys(),不要用 set
空集合怎么写?set(),不是 {}
两者共同点?底层都是哈希表,查找 O(1),元素/键必须可哈希

记住:dict 是有序的键值对容器,set 是无序的唯一元素容器。两者都靠哈希表实现,所以查找快;但 set 不保证顺序,需要顺序时用 dictdict.fromkeys()