数据容器概述

能够存储多个数据(元素)的数据类型,即"容纳"多份数据的容器

在编程的过程中,我们需要对批量的数据进行统一的管理,这时候不能再用单一变量去一个个存储,不仅麻烦且不易维护。数据容器就是为了解决这个问题而存在的——它可以把多个数据组织在一起,方便统一操作。

Python 中常用的数据容器分为以下 5 类:

容器 类型标识 特点 可变性 元素是否有序 元素是否可重复
列表 list 最通用的序列容器 可变 有序 可重复
元组 tuple 不可修改的序列容器 不可变 有序 可重复
字符串 str 字符组成的序列容器 不可变 有序 可重复
集合 set 去重、数学运算 可变 无序 不可重复
字典 dict 键值对映射容器 可变 有序(Python 3.7+) 键不可重复
1
2
3
4
5
6
7
8
9
10
11
12
# 五种数据容器的直观对比
list_data = [1, 2, 3] # 列表:用 [] 定义
tuple_data = (1, 2, 3) # 元组:用 () 定义
str_data = "hello" # 字符串:用 "" 定义
set_data = {1, 2, 3} # 集合:用 {} 定义(无键值对)
dict_data = {"a": 1, "b": 2} # 字典:用 {} 定义(有键值对)

print(type(list_data)) # 输出 <class 'list'>
print(type(tuple_data)) # 输出 <class 'tuple'>
print(type(str_data)) # 输出 <class 'str'>
print(type(set_data)) # 输出 <class 'set'>
print(type(dict_data)) # 输出 <class 'dict'>

列表(List)

列表是 Python 中最常用的数据容器,可以存储任意类型、任意数量的元素,支持增删改查等操作

列表是一个有序可变的序列容器,使用方括号 [] 定义,元素之间用逗号分隔。

  1. 列表的定义
1
2
3
4
5
6
7
8
9
10
11
12
# 定义列表的几种方式
empty_list = [] # 空列表
nums = [1, 2, 3, 4, 5] # 纯数字列表
mixed = [1, "hello", 3.14, True] # 混合类型列表
nested = [[1, 2], [3, 4], [5, 6]] # 嵌套列表(二维列表)

# 使用 list() 构造函数
chars = list("abc") # 将字符串转为列表
print(chars) # 输出 ['a', 'b', 'c']

range_list = list(range(1, 6)) # 将 range 转为列表
print(range_list) # 输出 [1, 2, 3, 4, 5]
  1. 列表的下标索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"""
列表通过下标(索引)访问元素:
- 正向索引:从左往右,从 0 开始计数
- 反向索引:从右往左,从 -1 开始计数
"""
fruits = ["苹果", "香蕉", "橘子", "葡萄", "西瓜"]

# 正向索引 0 1 2 3 4
# 反向索引 -5 -4 -3 -2 -1

print(fruits[0]) # 输出 苹果
print(fruits[2]) # 输出 橘子
print(fruits[-1]) # 输出 西瓜(倒数第一个)
print(fruits[-3]) # 输出 橘子(倒数第三个)

# 嵌套列表的索引
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[1][2]) # 输出 6(第二个列表的第三个元素)
  1. 列表的常用方法 — 查询与遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fruits = ["苹果", "香蕉", "橘子"]

# 获取列表长度
print(len(fruits)) # 输出 3

# 遍历列表
for fruit in fruits:
print(fruit)
# 输出:
# 苹果
# 香蕉
# 橘子

# 带索引的遍历
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 输出:
# 0: 苹果
# 1: 香蕉
# 2: 橘子

# 查找元素索引
print(fruits.index("香蕉")) # 输出 1

# 统计元素出现次数
nums = [1, 2, 3, 2, 1, 2]
print(nums.count(2)) # 输出 3
  1. 列表的常用方法 — 增加元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nums = [1, 2, 3]

# append():在末尾追加一个元素
nums.append(4)
print(nums) # 输出 [1, 2, 3, 4]

# insert():在指定位置插入元素
nums.insert(0, 0) # 在下标0处插入0
print(nums) # 输出 [0, 1, 2, 3, 4]

# extend():在末尾追加另一个容器中的所有元素
nums.extend([5, 6])
print(nums) # 输出 [0, 1, 2, 3, 4, 5, 6]

# 使用 + 拼接列表(产生新列表,不修改原列表)
a = [1, 2]
b = [3, 4]
c = a + b
print(c) # 输出 [1, 2, 3, 4]
  1. 列表的常用方法 — 删除元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
nums = [10, 20, 30, 40, 50]

# pop():弹出指定下标的元素(默认最后一个),返回被删除的值
last = nums.pop()
print(last) # 输出 50
print(nums) # 输出 [10, 20, 30, 40]

second = nums.pop(1)
print(second) # 输出 20
print(nums) # 输出 [10, 30, 40]

# remove():删除第一个匹配的值
nums = [1, 2, 3, 2, 4]
nums.remove(2) # 删除第一个出现的 2
print(nums) # 输出 [1, 3, 2, 4]

# del 语句:按索引删除
nums = [10, 20, 30]
del nums[1]
print(nums) # 输出 [10, 30]

# clear():清空列表
nums.clear()
print(nums) # 输出 []
  1. 列表的常用方法 — 修改与排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 修改元素:直接通过索引赋值
fruits = ["苹果", "香蕉", "橘子"]
fruits[1] = "草莓"
print(fruits) # 输出 ['苹果', '草莓', '橘子']

# reverse():反转列表
nums = [1, 2, 3, 4, 5]
nums.reverse()
print(nums) # 输出 [5, 4, 3, 2, 1]

# sort():原地排序(修改原列表)
nums = [3, 1, 4, 1, 5, 9]
nums.sort()
print(nums) # 输出 [1, 1, 3, 4, 5, 9]
nums.sort(reverse=True)
print(nums) # 输出 [9, 5, 4, 3, 1, 1]

# sorted():内置函数排序(产生新列表,不修改原列表)
nums = [3, 1, 4]
sorted_nums = sorted(nums)
print(sorted_nums) # 输出 [1, 3, 4]
print(nums) # 输出 [3, 1, 4] 原列表不变
  1. 列表推导式

一种简洁地创建列表的方式,可以在一行代码内完成循环+条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 基本语法:[表达式 for 变量 in 可迭代对象 if 条件]

# 生成 1~10 的平方列表
squares = [x ** 2 for x in range(1, 11)]
print(squares) # 输出 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 带条件的列表推导式
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens) # 输出 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# 嵌套循环的列表推导式
pairs = [(x, y) for x in range(1, 3) for y in "ab"]
print(pairs) # 输出 [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

# 带条件转换
grades = [85, 92, 78, 60, 45, 95]
result = ["及格" if g >= 60 else "不及格" for g in grades]
print(result) # 输出 ['及格', '及格', '及格', '及格', '不及格', '及格']

元组(Tuple)

元组是"不可变"的序列容器,一旦定义,其元素不可被修改、添加或删除

元组使用圆括号 () 定义,元素之间用逗号分隔。由于不可修改,元组比列表更安全、占用内存更小,适合存储不需要改变的数据。

  1. 元组的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 定义元组的几种方式
empty_tuple = () # 空元组
single = (1,) # 单元素元组(逗号不能省略!)
nums = (1, 2, 3) # 多元素元组
without_parens = 1, 2, 3 # 可以省略括号
mixed = (1, "hello", 3.14) # 混合类型

# 注意:单元素必须加逗号,否则不是元组!
not_tuple = (1) # 这是 int,不是元组
print(type(not_tuple)) # 输出 <class 'int'>
print(type((1,))) # 输出 <class 'tuple'>

# 使用 tuple() 构造函数
chars = tuple("abc")
print(chars) # 输出 ('a', 'b', 'c')

list_to_tuple = tuple([1, 2, 3])
print(list_to_tuple) # 输出 (1, 2, 3)
  1. 元组的基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
info = ("小明", 18, "北京", 95.5)

# 通过索引访问
print(info[0]) # 输出 小明
print(info[-1]) # 输出 95.5

# 获取长度
print(len(info)) # 输出 4

# count() 和 index()
nums = (1, 2, 3, 2, 1, 2)
print(nums.count(2)) # 输出 3
print(nums.index(3)) # 输出 2

# 遍历元组
for item in info:
print(item)

# 解包(Unpacking)
name, age, city, score = info
print(name, age, city, score) # 输出 小明 18 北京 95.5
  1. 元组的不可变性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
t = (1, 2, 3)

# 以下操作都会报错:
# t[0] = 10 # TypeError: 不支持修改
# t.append(4) # AttributeError: 元组没有 append 方法
# del t[1] # TypeError: 不支持删除元素

# 但是可以重新赋值变量(指向新的元组)
t = (4, 5, 6) # 这是创建新元组,不是修改原元组
print(t) # 输出 (4, 5, 6)

# 可变类型嵌套在元组中,可以修改可变类型的内部元素
t = (1, [2, 3], 4)
t[1][0] = 99 # 修改的是列表内部元素,不影响元组结构
print(t) # 输出 (1, [99, 3], 4)

字符串(String)

字符串是字符组成的不可变序列容器,支持索引、切片等序列操作

字符串在前面的笔记中已经接触过。作为数据容器来看,字符串本质上是字符的序列,因此也支持下标索引和切片操作。

  1. 字符串作为序列容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
text = "Python"

# 索引访问(与列表、元组完全一致)
print(text[0]) # 输出 P
print(text[-1]) # 输出 n
print(len(text)) # 输出 6

# 遍历字符
for ch in text:
print(ch, end=" ") # 输出 P y t h o n
print()

# 成员判断
print("th" in text) # 输出 True
print("xy" in text) # 输出 False
  1. 字符串的常用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
s = "  Hello Python World  "

# 大小写转换
print(s.upper()) # 输出 HELLO PYTHON WORLD
print(s.lower()) # 输出 hello python world
print(s.title()) # 输出 Hello Python World

# 去除空白
print(s.strip()) # 输出 Hello Python World
print(s.lstrip()) # 输出去除左边空白
print(s.rstrip()) # 输出去除右边空白

# 查找与替换
print(s.find("Python")) # 输出 8(返回第一次出现的位置)
print(s.replace("World", "Python")) # 输出 Hello Python Python

# 分割与拼接
words = "苹果,香蕉,橘子"
fruits_list = words.split(",") # 按逗号分割
print(fruits_list) # 输出 ['苹果', '香蕉', '橘子']

joined = "-".join(fruits_list) # 用 - 拼接
print(joined) # 输出 苹果-香蕉-橘子

# 判断方法
print("abc".isalpha()) # 输出 True(全是字母)
print("123".isdigit()) # 输出 True(全是数字)
print("abc123".isalnum()) # 输出 True(字母+数字)

# 格式化
name, age = "小明", 18
print("我叫{},今年{}岁".format(name, age)) # format 格式化
print(f"我叫{name},今年{age}岁") # f-string 格式化(推荐)

序列的切片操作 重点

切片(Slice)可以从序列容器中一次性取出多个元素,生成一个新的序列对象

列表、元组、字符串都是序列类型,它们共同支持切片操作。切片是 Python 序列容器最强大的特性之一。

  1. 切片的基本语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
序列[起始位置 : 结束位置 : 步长]

- 起始位置:包含,默认为 0(可省略)
- 结束位置:不包含,默认为序列长度(可省略)
- 步长:每次跨越的元素个数,默认为 1(可省略)
- 切片不会修改原序列,而是生成一个新的序列对象
"""
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(nums[2:7]) # 输出 [2, 3, 4, 5, 6] 下标2到6(不含7)
print(nums[:5]) # 输出 [0, 1, 2, 3, 4] 从开头到下标4
print(nums[5:]) # 输出 [5, 6, 7, 8, 9] 从下标5到末尾
print(nums[:]) # 输出 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 完整复制
print(nums[::2]) # 输出 [0, 2, 4, 6, 8] 步长为2,隔一个取一个
print(nums[::-1]) # 输出 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 逆向步长,反转序列
  1. 三种序列的切片对比
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 列表切片
lst = [1, 2, 3, 4, 5]
print(lst[1:4]) # 输出 [2, 3, 4]
print(lst[::-1]) # 输出 [5, 4, 3, 2, 1]

# 元组切片
tup = (1, 2, 3, 4, 5)
print(tup[1:4]) # 输出 (2, 3, 4)
print(tup[::2]) # 输出 (1, 3, 5)

# 字符串切片
text = "Hello World"
print(text[0:5]) # 输出 Hello
print(text[::-1]) # 输出 dlroW olleH
print(text[::2]) # 输出 HloWrd
  1. 切片的实用技巧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 取前n个元素
first_three = nums[:3]
print(first_three) # 输出 [1, 2, 3]

# 取后n个元素
last_three = nums[-3:]
print(last_three) # 输出 [8, 9, 10]

# 反转序列(字符串也适用)
reversed_nums = nums[::-1]
print(reversed_nums) # 输出 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

# 删除序列中的某一段(通过切片赋值)
nums[2:5] = [] # 删除下标 2~4 的元素
print(nums) # 输出 [1, 2, 6, 7, 8, 9, 10]

# 插入多个元素(通过切片赋值)
nums[2:2] = [3, 4, 5] # 在下标2处插入
print(nums) # 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

集合(Set)

集合是一种无序、不可重复的数据容器,支持并集、交集、差集等数学中的集合运算

集合使用花括号 {} 定义(空集合必须用 set()),元素必须是不可变类型,且自动去重。

  1. 集合的定义与基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义集合
empty_set = set() # 空集合(不能用 {},那是空字典)
nums = {1, 2, 3, 4, 5} # 普通集合
mixed = {1, "hello", 3.14, (1, 2)} # 元素必须不可变

# 注意:集合自动去重
s = {1, 1, 2, 2, 3, 3}
print(s) # 输出 {1, 2, 3}

# 注意:集合是无序的,不支持下标索引
# print(s[0]) # TypeError: 集合不支持索引访问

# 成员判断(非常高效,基于哈希表)
print(2 in s) # 输出 True
print(10 in s) # 输出 False
  1. 集合的常用方法 — 增删改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
s = {1, 2, 3}

# add():添加一个元素
s.add(4)
print(s) # 输出 {1, 2, 3, 4}
s.add(2) # 重复元素不会生效
print(s) # 输出 {1, 2, 3, 4}

# update():批量添加(添加容器中的每个元素)
s.update([5, 6, 7])
print(s) # 输出 {1, 2, 3, 4, 5, 6, 7}

# remove():删除指定元素(元素不存在会报错)
s.remove(7)
print(s) # 输出 {1, 2, 3, 4, 5, 6}

# discard():删除指定元素(元素不存在不会报错)
s.discard(10) # 不会报错

# pop():随机弹出一个元素
popped = s.pop()
print(popped) # 输出被删除的元素(不确定是哪个)

# clear():清空集合
s.clear()
print(s) # 输出 set()
  1. 集合运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# 并集:两个集合中的所有元素
print(a | b) # 输出 {1, 2, 3, 4, 5, 6}
print(a.union(b)) # 同上

# 交集:两个集合的共同元素
print(a & b) # 输出 {3, 4}
print(a.intersection(b)) # 同上

# 差集:只在 a 中、不在 b 中的元素
print(a - b) # 输出 {1, 2}
print(a.difference(b)) # 同上

# 对称差集:只在其中一个集合中的元素
print(a ^ b) # 输出 {1, 2, 5, 6}
print(a.symmetric_difference(b)) # 同上

# 判断子集和超集
print({1, 2} <= a) # 输出 True(子集)
print(a >= {1, 2}) # 输出 True(超集)
  1. 集合的应用场景
1
2
3
4
5
6
7
8
9
10
11
12
13
# 去重
nums = [1, 2, 2, 3, 3, 3, 4]
unique = list(set(nums))
print(unique) # 输出 [1, 2, 3, 4](顺序可能变化)

# 成员判断(比列表快得多)
large_data = set(range(1000000))
print(999999 in large_data) # 几乎瞬间完成

# 统计不重复元素
words = ["苹果", "香蕉", "苹果", "橘子", "香蕉"]
unique_count = len(set(words))
print(f"不重复的有 {unique_count} 种") # 输出 不重复的有 3 种

字典(Dictionary)

字典是一种以键值对(Key-Value Pair)存储数据的映射型容器,通过键(Key)来快速访问值(Value)

字典使用花括号 {} 定义,每个元素由 key: value 组成。键必须是不可变类型(通常为字符串或数字),值可以是任意类型。Python 3.7+ 字典默认有序(按插入顺序)。

  1. 字典的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 定义字典的几种方式
empty_dict = {} # 空字典
empty_dict2 = dict() # 用 dict() 创建空字典

student = { # 普通字典
"name": "小明",
"age": 18,
"score": 95
}

# 用 dict() 创建
person = dict(name="小红", age=20, city="北京")
print(person) # 输出 {'name': '小红', 'age': 20, 'city': '北京'}

# 从键值对列表创建
pairs = [("a", 1), ("b", 2), ("c", 3)]
d = dict(pairs)
print(d) # 输出 {'a': 1, 'b': 2, 'c': 3}
  1. 字典的访问与遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
student = {"name": "小明", "age": 18, "score": 95}

# 通过键访问值
print(student["name"]) # 输出 小明
print(student.get("age")) # 输出 18

# get() 与 [] 的区别
print(student.get("level", "未知")) # 键不存在返回默认值 "未知"
# print(student["level"]) # 键不存在会报 KeyError 错误

# 遍历键
for key in student.keys():
print(key, end=" ") # 输出 name age score
print()

# 遍历值
for value in student.values():
print(value, end=" ") # 输出 小明 18 95
print()

# 遍历键值对(最常用)
for key, value in student.items():
print(f"{key}: {value}")
# 输出:
# name: 小明
# age: 18
# score: 95
  1. 字典的增删改操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
student = {"name": "小明", "age": 18}

# 新增键值对
student["score"] = 95
print(student) # 输出 {'name': '小明', 'age': 18, 'score': 95}

# 修改值
student["age"] = 19
print(student) # 输出 {'name': '小明', 'age': 19, 'score': 95}

# update():批量更新(键存在则更新,不存在则新增)
student.update({"age": 20, "city": "北京"})
print(student) # 输出 {'name': '小明', 'age': 20, 'score': 95, 'city': '北京'}

# pop():删除键值对,返回被删除的值
city = student.pop("city")
print(city) # 输出 北京
print(student) # 输出 {'name': '小明', 'age': 20, 'score': 95}

# popitem():弹出最后一个键值对(Python 3.7+)
item = student.popitem()
print(item) # 输出 ('score', 95)

# del 语句:按键删除
del student["age"]
print(student) # 输出 {'name': '小明'}

# clear():清空字典
student.clear()
print(student) # 输出 {}
  1. 字典推导式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基本语法:{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}

# 创建平方字典
squares = {x: x ** 2 for x in range(1, 6)}
print(squares) # 输出 {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 带条件的字典推导式
even_squares = {x: x ** 2 for x in range(1, 11) if x % 2 == 0}
print(even_squares) # 输出 {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# 反转字典的键和值
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {v: k for k, v in original.items()}
print(reversed_dict) # 输出 {1: 'a', 2: 'b', 3: 'c'}

映射类型 了解即可

映射(Mapping)是一种通过键直接查找对应值的数据结构,字典是 Python 唯一的原生映射类型

字典之所以被称为"映射"类型,是因为它实现了键 → 值的对应关系,就像现实中的字典:通过一个"字"(键)来查找它的"释义"(值)。

  1. 映射的核心特性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""
映射类型的三个核心特性:
1. 键唯一:同一个键不能出现多次
2. 通过键快速查找值:类似用查字典,不需要遍历
3. 键必须是不可变类型:因为内部使用哈希表实现
"""
# 键是唯一的:重复赋值会覆盖
d = {"a": 1, "b": 2, "a": 3}
print(d) # 输出 {'a': 3, 'b': 2} —— 后面的 "a" 覆盖了前面的

# 键必须是不可变类型(可哈希)

"""
为什么字典的键必须是不可变类型?

字典的内部实现基于"哈希表"(Hash Table)。哈希表的工作原理是:
1. 通过 hash() 函数计算键的哈希值(一个固定长度的整数)
2. 根据哈希值快速定位到存储位置
3. 如果键是可变的,其哈希值也会变化,导致之前存储的数据"丢失"

所以要求键必须是"可哈希的"(hashable),即该对象拥有一个在其生命周期
内永不改变的哈希值。只有不可变类型满足这个条件。
"""

# 查看一个对象的哈希值
print(hash("hello")) # 输出一个整数,如 -5678451840116190856
print(hash((1, 2, 3))) # 输出一个整数,如 529344067295497451
print(hash(42)) # 输出 42(整数的哈希值就是它本身)

# 可变类型的对象无法计算哈希值,会报错
# print(hash([1, 2, 3])) # TypeError: unhashable type: 'list'
# print(hash({"a": 1})) # TypeError: unhashable type: 'dict'
# print(hash({1, 2, 3})) # TypeError: unhashable type: 'set'

# 可哈希(可作为键)的类型总结
works = {
1: "整数可以", # int 不可变,可哈希
"s": "字符串可以", # str 不可变,可哈希
(1, 2): "元组可以", # tuple 不可变,可哈希
3.14: "浮点数可以", # float 不可变,可哈希
True: "布尔值可以", # bool 不可变,可哈希
None: "None 可以", # None 不可变,可哈希
}

# 不可哈希(不能作为键)的类型
# fails = {
# [1, 2]: "列表不行", # TypeError: list 可变,不可哈希
# {1, 2}: "集合不行", # TypeError: set 可变,不可哈希
# {"k": "v"}: "字典不行", # TypeError: dict 可变,不可哈希
# }

# 映射的高效查找(无论字典多大,查找时间几乎不变)
data = {f"key_{i}": i for i in range(1000000)}
print("key_999999" in data) # 几乎瞬间完成
  1. 字典的常用技巧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 计数器模式(统计词频)
words = ["苹果", "香蕉", "苹果", "橘子", "香蕉", "苹果"]
counter = {}
for word in words:
counter[word] = counter.get(word, 0) + 1
print(counter)
# 输出 {'苹果': 3, '香蕉': 2, '橘子': 1}

# 字典存储结构化数据(替代简单的类)
users = {
101: {"name": "小明", "role": "admin", "login_count": 15},
102: {"name": "小红", "role": "user", "login_count": 8},
103: {"name": "小刚", "role": "user", "login_count": 23},
}

# 查找活跃用户(登录次数 > 10)
active_users = []
for uid, info in users.items():
if info["login_count"] > 10:
active_users.append(info["name"])
print(f"活跃用户:{active_users}") # 输出 活跃用户:['小明', '小刚']

# 安全的嵌套访问
user = {"name": "小明", "profile": {"age": 18}}
print(user.get("profile", {}).get("age", "未知")) # 输出 18
print(user.get("profile", {}).get("score", "未知")) # 输出 未知

数据容器对比总结

每种数据容器都有各自的特点和适用场景,根据需求选择合适的容器

  1. 五大容器全面对比
特性 列表 元组 字符串 集合 字典
定义符号 [] () "" / '' {} {k: v}
类型名 list tuple str set dict
有序否 有序 有序 有序 无序 有序(3.7+)
可修改
可重复 键否/值是
下标索引 支持 支持 支持 不支持 不支持(按键取)
切片 支持 支持 支持 不支持 不支持
成员判断 in in in in in(查键)
  1. 通用操作(所有容器都支持)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 所有容器都支持的操作
lst = [1, 2, 3]
tup = (1, 2, 3)
s = "hello"
st = {1, 2, 3}
d = {"a": 1, "b": 2}

# len():查看元素个数
print(len(lst), len(tup), len(s), len(st), len(d))
# 输出 3 3 5 3 2

# in / not in:成员判断
print(1 in lst) # 输出 True
print("h" in s) # 输出 True
print(1 in st) # 输出 True
print("a" in d) # 输出 True(字典判断的是键)

# max() / min():最大/最小值
nums = [3, 1, 4, 1, 5]
print(max(nums)) # 输出 5
print(min(nums)) # 输出 1

# sorted():排序(返回新列表)
print(sorted(nums)) # 输出 [1, 1, 3, 4, 5]

# 类型转换函数
print(list((1, 2, 3))) # 元组 → 列表
print(tuple([1, 2, 3])) # 列表 → 元组
print(set([1, 2, 2, 3])) # 列表 → 集合(去重)
print(list({"a": 1, "b": 2})) # 字典 → 列表(只取键)
  1. 如何选择合适的容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"""
根据需求选择最合适的容器:

├── 需要按位置存储,可能修改内容?
│ └── 是 → 使用 列表(list)
│ 否 → 使用 元组(tuple)

├── 处理文本(字符序列)?
│ └── 是 → 使用 字符串(str)

├── 需要去重、做数学集合运算?
│ └── 是 → 使用 集合(set)

└── 需要通过键快速查找值?
└── 是 → 使用 字典(dict)
"""
# 实际场景举例
# 购物车(可增删改) → 列表
cart = ["苹果", "香蕉", "橘子"]
cart.append("葡萄") # 灵活添加

# 坐标点(不可变) → 元组
point = (120.1, 30.2)

# 标签列表(去重) → 集合
tags = {"Python", "编程", "教程"}
tags.add("Python") # 不会重复

# 学生信息(按名称查找) → 字典
students = {"小明": 95, "小红": 88, "小刚": 76}
print(students["小明"]) # 快速查找

综合练习

将所学知识融会贯通,通过实际案例巩固数据容器的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 学生成绩分析系统
"""
使用多种数据容器综合处理学生成绩数据
"""
# 初始数据
scores = [85, 92, 78, 60, 95, 45, 88, 73, 58, 91]

# 1. 使用列表存储成绩,计算基本统计
total = sum(scores)
count = len(scores)
avg = total / count
print(f"总人数:{count},平均分:{avg:.1f}")

# 2. 使用集合去重,统计不同的分数
unique_scores = set(scores)
print(f"不同分数的种类:{len(unique_scores)}")

# 3. 使用字典进行等级分类统计
grade_count = {"优秀": 0, "良好": 0, "中等": 0, "及格": 0, "不及格": 0}
for score in scores:
if score >= 90:
grade_count["优秀"] += 1
elif score >= 80:
grade_count["良好"] += 1
elif score >= 70:
grade_count["中等"] += 1
elif score >= 60:
grade_count["及格"] += 1
else:
grade_count["不及格"] += 1

for grade, num in grade_count.items():
print(f" {grade}{num}人")

# 4. 使用元组存储前3名(不变更)
sorted_scores = sorted(scores, reverse=True)
top3 = tuple(sorted_scores[:3])
print(f"前三名成绩:{top3}")

# 5. 使用列表推导式统计及格人数
passed_count = len([s for s in scores if s >= 60])
print(f"及格率:{passed_count / count * 100:.1f}%")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 词频统计与排序
"""
统计一段文本中每个词的词频,按频率从高到低排序
"""
text = """
Python is an easy to learn powerful programming language
It has efficient high-level data structures and a simple
but effective approach to object-oriented programming
Python is an interpreted language
"""

# 1. 处理文本:转小写、分词
words = text.lower().split()
print(f"总词数:{len(words)}")

# 2. 使用字典统计词频
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1

# 3. 使用集合去除停用词
stopwords = {"is", "an", "to", "a", "and", "it", "but", "the"}
for sw in stopwords:
word_count.pop(sw, None) # 删除停用词

# 4. 按频率排序(使用 sorted + lambda)
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)

print("\n词频统计 TOP 5:")
for word, count in sorted_words[:5]:
print(f" {word}:出现 {count} 次")

数据容器是 Python 的核心基础。列表灵活多变、元组安全高效、字符串处理文本、集合适配去重与数学运算、字典实现快速键值映射。理解每种容器的特性和适用场景,才能在实际编程中做出最优选择。

Python Study Note 系列文章

  1. Python Study Note
  2. Python 函数使用(四)
  3. Python 判断语句(二)
  4. Python 基础语法(一)
  5. Python 异常处理(七)
  6. Python 循环语句(三)
  7. Python 数据容器(五)
  8. Python 文件基础操作(六)
  9. Python 模块与包(八)
  10. Python 类型注解(十)
  11. Python 面向对象(九)重点
  12. Python 高阶技巧(十一)