2360 字
12 分钟
常用数据结构
NOTE本文对应仓库 Day08~13:列表、元组、字符串、集合、字典。这五大结构是 Python 日常编程的绝对主力,面试也是高频考点,务必熟练掌握它们的方法和相互转换。
五大结构速览
| 结构 | 字面量 | 有序 | 可变 | 可重复 | 典型用途 |
|---|---|---|---|---|---|
| 列表 list | [1, 2, 3] | ✅ | ✅ | ✅ | 通用序列、栈 |
| 元组 tuple | (1, 2, 3) | ✅ | ❌ | ✅ | 不可变记录、多返回值 |
| 字符串 str | "abc" | ✅ | ❌ | ✅ | 文本 |
| 集合 set | {1, 2, 3} | ❌ | ✅ | ❌ | 去重、交并差 |
| 字典 dict | {"k": "v"} | ✅(3.7+) | ✅ | 键唯一 | 键值映射 |
一、列表(list)
创建与运算
# 创建nums = [1, 2, 3, 4, 5]mixed = [1, "two", 3.0, True, None] # 可混合类型empty = [] # 或 list()
# 运算print(nums + [6, 7]) # 拼接:[1,2,3,4,5,6,7]print(nums * 2) # 重复:[1,2,3,4,5,1,2,3,4,5]print(3 in nums) # 成员运算:Trueprint(len(nums)) # 长度:5print(max(nums), min(nums), sum(nums)) # 15 的最大/最小/求和索引与切片
nums = [0, 1, 2, 3, 4, 5]# 索引:从 0 开始,负数表示从末尾print(nums[0]) # 0print(nums[-1]) # 5(最后一个)
# 切片 [start:stop:step],左闭右开print(nums[1:4]) # [1, 2, 3]print(nums[:3]) # [0, 1, 2](省略 start)print(nums[3:]) # [3, 4, 5](省略 stop)print(nums[::2]) # [0, 2, 4](步长 2)print(nums[::-1]) # [5,4,3,2,1,0](反转)常用方法
nums = [3, 1, 2]
# 增nums.append(4) # 末尾添加:[3,1,2,4]nums.insert(0, 9) # 指定位置插入:[9,3,1,2,4]nums.extend([5, 6]) # 扩展(合并另一个列表)
# 删nums.remove(9) # 删除第一个值为 9 的元素popped = nums.pop() # 弹出末尾元素并返回popped = nums.pop(0) # 弹出指定索引del nums[0] # del 删除nums.clear() # 清空
# 查nums = [1, 2, 3, 2]print(nums.index(2)) # 第一次出现的索引:1print(nums.count(2)) # 出现次数:2
# 排序与反转nums.sort() # 原地升序排序:[1,2,2,3]nums.sort(reverse=True) # 降序nums.reverse() # 原地反转sorted_nums = sorted(nums) # 返回新列表,不改原列表nums.sort(key=lambda x: -x) # 自定义排序规则列表生成式(推导式)
# 基本形式:[表达式 for 变量 in 可迭代对象]squares = [x ** 2 for x in range(10)] # [0,1,4,...,81]
# 带条件过滤evens = [x for x in range(20) if x % 2 == 0] # 偶数
# 嵌套matrix = [[i * j for j in range(3)] for i in range(3)]
# 相比 map/filter 更 Pythonicnums = [1, 2, 3, 4]doubled = [n * 2 for n in nums] # 推荐# doubled = list(map(lambda n: n*2, nums)) # 等价但不如上面直观嵌套列表(二维)
# 3×3 矩阵matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9],]print(matrix[1][2]) # 6(第 2 行第 3 列)
# 遍历for row in matrix: for val in row: print(val, end=" ") print()WARNING创建二维列表不要用
[[0]*3]*3!这样三行是同一个对象的引用,改一行三行都变。正确写法:[[0]*3 for _ in range(3)]。
二、元组(tuple)
定义与运算
# 定义(小括号,但括号可省略)t = (1, 2, 3)t2 = 1, 2, 3 # 等价single = (42,) # 单元素元组必须加逗号!(42) 是整数 42
# 元组不可变:不能增删改# t[0] = 99 # TypeError
# 运算和列表一样(+ * in 索引 切片),但没有增删改方法print(t + (4,)) # (1,2,3,4)print(t[0], t[-1]) # 1 3打包与解包
# 打包:多个值组成元组point = 3, 4
# 解包:元组值分别赋给多个变量x, y = point # x=3, y=4print(x, y)
# 交换变量(最经典的用法)a, b = 1, 2a, b = b, a # 现在 a=2, b=1
# 星号解包(接收剩余元素)first, *rest = [1, 2, 3, 4, 5]print(first) # 1print(rest) # [2, 3, 4, 5]
# 函数返回多个值本质就是返回元组def min_max(nums): return min(nums), max(nums)lo, hi = min_max([3, 1, 4, 1, 5])元组 vs 列表
| 对比 | 元组 tuple | 列表 list |
|---|---|---|
| 可变性 | 不可变 | 可变 |
| 性能 | 更快、更省内存 | 稍慢 |
| 安全性 | 数据不会被意外修改 | 可能被修改 |
| 可哈希 | 是(可作字典的键) | 否 |
| 使用场景 | 固定数据、多返回值、字典键 | 需要增删改的序列 |
三、字符串(str)
定义与特殊表示
s1 = 'single quotes's2 = "double quotes"s3 = """多行字符串"""
# 转义字符print("换行\n制表\t反斜杠\\ 引号\"")
# 原始字符串(r 前缀,不转义,常用于正则/路径)path = r"C:\new\test.txt" # 不会把 \n \t 当转义print(path)运算与索引切片
s = "Hello, Python"print(s + "!") # 拼接print(s * 2) # 重复print(len(s)) # 长度:13print("Python" in s) # 成员运算:Trueprint(s[0]) # Hprint(s[-6:]) # Pythonprint(s[7:]) # Python(切片)常用方法(按用途分类)
s = " Hello World "
# 大小写"abc".upper() # "ABC""ABC".lower() # "abc""hello world".title() # "Hello World""Hello".swapcase() # "hELLO"
# 修剪(去空白)s.strip() # "Hello World"(两端)s.lstrip() # 去左s.rstrip() # 去右
# 查找与判断"Hello".find("ll") # 2(找不到返回 -1)"Hello".index("ll") # 2(找不到抛异常)"Hello".startswith("He") # True"Hello".endswith("lo") # True"123".isdigit() # True"abc".isalpha() # True"abc123".isalnum() # True
# 替换"a-b-c".replace("-", "+") # "a+b+c"
# 拆分与合并"a,b,c".split(",") # ['a', 'b', 'c']"-".join(['a', 'b', 'c']) # "a-b-c"
# 格式化(三种方式)name, age = "Ethan", 25"我是%s,%d岁" % (name, age) # 旧式"我是{},{}岁".format(name, age) # formatf"我是{name},{age}岁" # f-string(推荐)编码与解码
# str(文本) ↔ bytes(字节)s = "你好,Python"b = s.encode("utf-8") # 编码为字节:b'\xe4\xbd\xa0...'s2 = b.decode("utf-8") # 解码回字符串print(len(s)) # 字符数:9print(len(b)) # 字节数:更多(中文 UTF-8 占 3 字节)四、集合(set)
创建与运算
# 创建(自动去重、无序)s = {1, 2, 3, 3, 2} # {1, 2, 3}s2 = set([1, 2, 2, 3]) # 从列表创建(去重)empty = set() # 注意:{} 是空字典,不是空集合!
# 去重是集合最常见的用途nums = [1, 2, 2, 3, 3, 3]unique = list(set(nums)) # [1, 2, 3]集合运算(数学)
a = {1, 2, 3, 4}b = {3, 4, 5, 6}
print(a & b) # 交集 {3, 4} a.intersection(b)print(a | b) # 并集 {1,2,3,4,5,6} a.union(b)print(a - b) # 差集 {1, 2} a.difference(b)print(a ^ b) # 对称差集 {1,2,5,6} a.symmetric_difference(b)
# 比较print({1, 2} <= a) # 子集:Trueprint(a >= {1, 2}) # 超集:True常用方法与不可变集合
s = {1, 2}s.add(3) # 添加s.update([4, 5]) # 批量添加s.remove(1) # 删除(不存在报错)s.discard(99) # 删除(不存在不报错)print(2 in s) # 成员运算(集合的 in 极快,O(1))
# 不可变集合 frozenset(可作字典的键)fs = frozenset([1, 2, 3])五、字典(dict)
创建与使用
# 创建person = {"name": "Ethan", "age": 25, "city": "Shanghai"}person2 = dict(name="Tom", age=30) # 关键字参数person3 = dict([("a", 1), ("b", 2)]) # 键值对序列empty = {} # 空字典
# 访问print(person["name"]) # Ethan# print(person["xxx"]) # 键不存在会 KeyErrorprint(person.get("xxx")) # None(推荐,不报错)print(person.get("xxx", "默认值")) # 键不存在返回默认值增删改查
person = {"name": "Ethan"}
# 增 / 改(键存在则改,不存在则增)person["age"] = 25person.update({"city": "SH", "age": 26}) # 批量更新
# 删del person["city"]age = person.pop("age") # 删除并返回值person.pop("xxx", None) # 键不存在给默认值,不报错person.clear() # 清空
# 查print("name" in person) # 判断键是否存在遍历
scores = {"语文": 90, "数学": 95, "英语": 88}
# 遍历键for key in scores: # 等价 scores.keys() print(key)
# 遍历值for val in scores.values(): print(val)
# 遍历键值对(最常用)for key, val in scores.items(): print(f"{key}: {val}")
# 字典生成式squared = {x: x ** 2 for x in range(5)} # {0:0, 1:1, 2:4, 3:9, 4:16}应用示例
# 统计词频words = ["apple", "banana", "apple", "cherry", "banana", "apple"]counter = {}for w in words: counter[w] = counter.get(w, 0) + 1print(counter) # {'apple': 3, 'banana': 2, 'cherry': 1}
# 用 collections.Counter 更简洁from collections import Counterprint(Counter(words)) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})print(Counter(words).most_common(2)) # 出现最多的 2 个结构之间的转换
# list ↔ tuple ↔ set ↔ strlst = [1, 2, 3]tpl = tuple(lst) # (1, 2, 3)st = set(lst) # {1, 2, 3}(去重)back = list(st)
# str → listlist("abc") # ['a', 'b', 'c']"abc".split() # 按空白拆"".join(['a', 'b']) # list → str
# dict 相关dict([("a", 1)]) # [('a',1)] → {'a':1}d = {"a": 1, "b": 2}list(d.keys()) # ['a', 'b']list(d.values()) # [1, 2]list(d.items()) # [('a',1), ('b',2)]常见问题 Q&A
Q1:列表和元组怎么选? A:数据需要修改用列表;数据固定不变(如坐标、配置、函数多返回值)用元组。元组更快、更安全,还能作字典的键。
Q2:{} 是空集合还是空字典?
A:是空字典!空集合必须用 set()。这是常见陷阱。
Q3:remove、pop、del 有什么区别?
A:remove(值) 按值删除;pop(索引) 删除并返回该元素(默认末尾);del list[i] 按索引删除且不返回。
Q4:sort() 和 sorted() 区别?
A:sort() 是列表方法,原地排序返回 None;sorted() 是内置函数,返回新列表,且适用于任何可迭代对象。
Q5:字典是有序的吗?
A:Python 3.7+ 字典保证按插入顺序遍历(3.6 是实现细节)。之前的版本无序,需有序要用 collections.OrderedDict。
Q6:为什么集合的 in 判断比列表快?
A:集合基于哈希表,in 是 O(1);列表是逐个比较,O(n)。频繁做成员判断时优先用集合。
复习卡片
TIP五大结构速记
- 列表:可变有序,
append/insert/remove/pop/sort,生成式[x for x in ...],切片[start:stop:step]- 元组:不可变,
(1,)单元素要加逗号,a,b = b,a解包交换,可作字典键- 字符串:不可变,
split/join/replace/strip/find,encode/decode转字节,f-string 格式化- 集合:无序去重,
& | - ^交并差对称差,in是 O(1),{}是空字典不是空集合- 字典:键值对,
get()安全取值,items()遍历,3.7+ 保持插入序- 切片通用:
[左闭:右开:步长],[::-1]反转- 去重:
list(set(x));统计:collections.Counter- 推导式:列表
[]、字典{k:v}、集合{}、生成器()都支持
TIP下一篇:函数、模块与面向对象 将讲解函数定义与参数、高阶函数、Lambda、装饰器、递归,以及面向对象编程(类、对象、继承、多态)。
返回 Python 学习路线总览 | 合集页