03 数据容器:列表、字符串、元组、集合与字典

03 数据容器:列表、字符串、元组、集合与字典

本节以练习代码 03.py 为主线,对应讲义《第2章03节 数据存储容器》:五大容器 list / str / tuple / set / dict,以及切片、推导式、组包解包等 Python 特色写法。

一、列表 list

1.1 定义与特点

  • [元素...] 定义;可以存储不同类型元素(数字、字符串、布尔、None 混装),且元素有序、可重复、可修改。
1
2
3
4
5
6
7
8
a = [10, 10, 12.5, 'hello', True, None]
for i in a:
print(i, type(i))
# 10 <class 'int'>
# 12.5 <class 'float'>
# hello <class 'str'>
# True <class 'bool'>
# None <class 'NoneType'>

1.2 索引与切片

  • 正向索引从 0 起,反向索引从 -1 起;越界报 IndexError。
  • 切片格式 [开始:结束:步长]:不包含结束位置;start 默认 0,end 默认末尾,step 默认 1;支持负索引。
1
2
3
4
print(a[0])          # 10
print(a[0:-2]) # [10, 10, 12.5, 'hello'] 不包含倒数第 2 个
print(a[0:-2:2]) # [10, 12.5] 步长 2 跳着取
print(a[-2:0:-1]) # [True, 'hello', 12.5, 10] 反向取

1.3 常用方法

方法 作用 示例
append(x) 尾部追加 a.append("python")
insert(i, x) 在指定索引之前插入 a.insert(2, 5)
remove(x) 移除第一个匹配到的值 a.remove(10)
sort() 原地排序(默认升序,reverse=True 降序) b.sort(reverse=True)
reverse() 原地反转 b.reverse()
1
2
3
4
5
6
7
8
a = [10, 10, 12.5, 'hello', True, None]
a.append("python") # [10, 10, 12.5, 'hello', True, None, 'python']
a.insert(2, 5) # [10, 10, 5, 12.5, 'hello', True, None, 'python']
a.remove(10) # 删第一个 10 → [10, 5, 12.5, 'hello', True, None, 'python']

b = [1, 9, 8, 5, 7, 6, 3]
b.sort(reverse=True) # [9, 8, 7, 6, 5, 3, 1]
b.reverse() # [1, 3, 5, 6, 7, 8, 9]

1.4 统计函数

  • min() / max() / sum() / len() 分别取最小、最大、求和、长度。
1
2
3
4
print(min(b))   # 1
print(max(b)) # 9
print(sum(b)) # 39
print(len(b)) # 7

1.5 合并、解包与存在判断

  • 合并:list1 + list2;或解包 [*list1, *list2](* 把列表拆成独立元素)。
  • 元素 in 列表 判断是否存在,返回布尔值。
  • print(*列表) 可直接把元素逐个展开输出。
1
2
3
4
5
c = a + b
c = [*b, *a] # 解包合并
print(*b) # 1 3 5 6 7 8 9
print(5 in b) # True
print(55 in b) # False

1.6 扩展解包(Python 特色)

  • z, *x, d = 列表:* 收集中间剩余元素成列表。
1
2
3
4
z, *x, d = b
print(z) # 1
print(x) # [3, 5, 6, 7, 8]
print(d) # 9

1.7 列表推导式

  • 一行生成新列表:[要插入的数据 for i in 数据集 if 条件],先写”放什么”,再写”从哪来”,最后”筛什么”。
1
2
3
4
5
a = [i * 2 for i in range(1, 11)]
print(a) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

a = [i * 2 for i in range(1, 11) if i % 2 == 1]
print(a) # 只取奇数 → [2, 6, 10, 14, 18]

二、字符串 str

2.1 不可变性

  • 字符串是字符容器:有序、可迭代、不可修改。upper() 等方法返回新字符串,原字符串不变,要接收必须重新赋值。
1
2
3
4
5
6
7
s = 'helloworld'
print(s[0:-3:2]) # hloo
print(s.upper()) # HELLOWORLD
print(s) # helloworld ← 原串没变
s = s.upper() # 重新赋值才生效
print(s) # HELLOWORLD
print(s.lower()) # helloworld

2.2 切片

  • 与列表同规则 [开始:结束:步长],不包含结束位置;s[::-1] 反转。
1
2
3
s = "Python"
print(s[0:5:2]) # Pto
print(s[::-1]) # nohtyP

2.3 常用方法

方法 作用 示例结果
find(子串) 返回第一次出现索引,找不到返回 -1 s.find('ASD') → -1
count(子串) 统计出现次数 s.count('OWO') → 1
upper() / lower() 转大写 / 小写(返回新串) —
split(分隔符) 按分隔符切成列表 'h*e*l*l*o'.split('*') → ['h','e','l','l','o']
strip(字符) 去除两端指定字符(默认空白) '***hello***'.strip('*') → hello
lstrip(字符) 只去左端 '***hello***'.lstrip('*') → hello***
replace(旧, 新) 替换所有匹配 '***hello***'.replace('*',' hi ') → hi hi hi hello hi hi hi
startswith(子串) 是否以指定子串开头 '***'.startswith('***') → True
1
2
3
4
5
6
7
8
s = 'helloworld'
print(s.find('ASD')) # -1
print(s.find('OWO')) # 4
print(s.count('OWO')) # 1

s = '***hello***'
print(s.startswith('***')) # True
print(s.startswith('***b')) # False

2.4 join():split 的反向操作(补充)

  • 分隔符.join(字符串列表) 把列表拼成一个字符串。
1
2
3
a = ['ds', 'sd', 'dd']
print(''.join(a)) # dssddd
print('-'.join(a)) # ds-sd-dd

三、元组 tuple

3.1 定义与特点

  • (元素...) 定义;有序、可重复、不可修改(适合固定配置等只读数据);支持索引与切片。
  • 方法只有两个:count() 统计次数、index() 查找索引(不存在报错)。
1
2
3
4
5
t1 = (1, 2, 5, 6, 9, 8, 4, 5)
print(t1[1:-2:2]) # (2, 6, 8) 切片结果还是元组
print(t1.count(5)) # 2
print(t1.index(6)) # 3
# t1.index(7) # 报错:不存在

3.2 单元素元组的坑

  • 单元素元组结尾必须加逗号:(5,) 才是元组;(1) 只是括号括起来的整数。
1
2
3
4
5
6
7
8
9
t2 = (1)
print(t2, type(t2)) # 1 <class 'int'>
t2 = ('saa')
print(t2, type(t2)) # saa <class 'str'>
t2 = (5,)
print(t2, type(t2)) # (5,) <class 'tuple'>

t = tuple() # 空元组
print(t) # ()

3.3 组包解包与交换

  • 组包:多个值合进容器(甚至可无括号 5, 7, 9, 1);解包:容器拆开赋给多个变量。
  • 变量交换/循环交换一行完成(Python 特色,Java/C++ 要临时变量)。
1
2
3
a, b, c = (10, 20, 30)
a, b, c = b, c, a
print(a, b, c) # 20 30 10

四、集合 set

4.1 定义与特点

  • {元素...} 定义;无序、不可重复、可修改;不支持索引访问。
  • 空集合必须用 set()——{} 是空字典(大坑)。
1
2
3
s1 = {1, 2, 'gm', 6256, 56.2}
print(s1, type(s1)) # {6256, 1, 2, 56.2, 'gm'} <class 'set'> ← 打印顺序无序
s2 = set() # 空集合

4.2 增删与去重

  • add() 添加(已存在则自动忽略,去重);remove() 移除(不存在报错);pop() 随机删。
1
2
3
4
5
6
s1.add(6)
s1.add(1) # 已存在,加不进去 → 集合元素唯一
print(s1) # {6256, 1, 2, 6, 56.2, 'gm'}

s1.remove(56.2)
# s1.remove(56.2) # 再删会报 KeyError

4.3 集合运算

  • 方法 difference() 差集 / intersection() 交集 / union() 并集;运算符 - 差集、& 交集、| 并集。
1
2
3
4
s2 = {1, 6}
print(s1.difference(s2)) # {6256, 2, 'gm'} 在 s1 不在 s2
print(s1.intersection(s2)) # {1, 6}
print(s1.union({1, 99})) # {6256, 1, 2, 'gm', 99, 6}

五、字典 dict

5.1 定义与取值

  • {key: value} 键值对存储;key 唯一(重复定义后面的覆盖前面的)且不能是可变类型;value 任意类型。
  • 取值:d[key](key 不存在抛 KeyError);d.get(key) 安全取值(不存在返回 None,可带默认值 d.get(key, 默认))。
1
2
3
d = {"name": "zhangsan", "age": 18, "h": 180.5}
print(d["name"]) # zhangsan
print(d.get("age")) # 18

5.2 增删改查

操作 写法 说明
添加/修改 d[key] = value key 不存在=新增,存在=修改
删除 d.pop(key) 删除并返回 value
删除 del d[key] 直接删
查询 d.keys() / d.values() / d.items() 取键 / 值 / 键值对
1
2
3
4
5
6
7
8
9
10
11
12
13
14
d[20] = 'hello'              # 添加(key 可以是数字)
print(d) # {'name': 'zhangsan', 'age': 18, 'h': 180.5, 20: 'hello'}

d.pop(20)
print(d) # {'name': 'zhangsan', 'age': 18, 'h': 180.5}

e = d.keys()
print(e, type(e)) # dict_keys(['name', 'age', 'h']) <class 'dict_keys'>

for k, v in d.items(): # 遍历键值对
print(k, v)
# name zhangsan
# age 18
# h 180.5

5.3 字典推导式(补充,讲义未提)

  • {key表达式: value表达式 for ...} 一行生成字典。
1
2
3
a = {x: x ** 2 for x in range(10)}
print(a)
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

六、易踩坑:引用与拷贝、sorted 与 sort

6.1 b = a 是引用不是拷贝

  • 直接赋值两个变量指向同一个列表,改一个两个都变;真拷贝用 .copy() 或切片 a[:]。
1
2
3
4
5
6
7
8
9
10
11
12
a = [1, 2, 5, 8, 3]
b = a
a[0] = 6
print(a) # [6, 2, 5, 8, 3]
print(b) # [6, 2, 5, 8, 3] ← b 也变了!

c = a.copy()
d = a[:] # 切片拷贝
a.append(100)
print(a) # [6, 2, 5, 8, 3, 100]
print(c) # [6, 2, 5, 8, 3] ← 不受影响
print(d) # [6, 2, 5, 8, 3]

6.2 sorted() vs list.sort()

  • list.sort() 原地排序且返回 None(别赋值给变量);sorted(列表) 返回新列表,原列表不变。
1
2
3
4
5
a = [6, 2, 5, 8, 3, 100]
print(sorted(a)) # [2, 3, 5, 6, 8, 100] 新列表
print(a) # [6, 2, 5, 8, 3, 100] 原列表不变
print(a.sort()) # None ← 坑!
print(a) # [2, 3, 5, 6, 8, 100] 原地已排序

七、补充小知识(教学讲解,讲义未提)

  • zip() 并行遍历 / 打包:把多个可迭代对象按位置配对,配 dict() 直接生成字典。
1
2
3
4
5
6
7
8
9
10
a = [1, 2, 3]
b = ['zhangsan', 'lisi', 'wangwu']
for id, name in zip(a, b):
print(id, name)
# 1 zhangsan
# 2 lisi
# 3 wangwu

x = dict(zip(a, b))
print(x) # {1: 'zhangsan', 2: 'lisi', 3: 'wangwu'}
  • 空容器真假:空列表/空字典/空集合都是 False,非空为 True([0] 非空,为真)。

今日总结

容器 定义 核心特点 关键操作
列表 list [元素] 有序、可重复、可变、可异构 append/insert/remove/sort/reverse;切片;推导式;+/* 合并
字符串 str "..." 有序、不可变 find/count/split/strip/replace/startswith;切片反转
元组 tuple (元素,) 有序、不可变 count/index;单元素加逗号;解包交换
集合 set {元素} 无序、去重、可变 add/remove;difference/intersection/union;&/|/-
字典 dict {k: v} key 唯一、可变 d[k]/get;增改 d[k]=v;pop/del;keys/values/items;推导式

三大 Python 特色必须掌握:切片 s[start:end:step](不含 end、可负索引)、推导式 [表达式 for i in 数据 if 条件]、组包解包 a, b = b, a / x, *y = 列表。

易踩坑:b = a 是引用要拷贝用 .copy()/a[:];sort() 返回 None 而 sorted() 返回新列表;空集合是 set() 不是 {};d[key] 不存在抛 KeyError 用 get;单元素元组要写 (5,)。