目录
[2.使用 list() 构造器](#2.使用 list() 构造器)
[3.列表推导式 ------ 一行代码批量生产](#3.列表推导式 —— 一行代码批量生产)
[4.用乘法 * 快速初始化](#4.用乘法 * 快速初始化)
[1.索引:从 0 开始的位置编号](#1.索引:从 0 开始的位置编号)
[3. 切片:取一段子列表](#3. 切片:取一段子列表)
[5. 统计出现次数:count()](#5. 统计出现次数:count())
[6. 判断是否存在:in 与 not in](#6. 判断是否存在:in 与 not in)
[1. 通过索引修改元素](#1. 通过索引修改元素)
[2. 在末尾追加:append()](#2. 在末尾追加:append())
[3. 在中间插入:insert()](#3. 在中间插入:insert())
[4. 扩展列表:extend() 与 +=](#4. 扩展列表:extend() 与 +=)
[5. 修改切片:一套强大的批量替换](#5. 修改切片:一套强大的批量替换)
[6. 其他修改方式:排序与反转](#6. 其他修改方式:排序与反转)
[1. pop(索引) ------ 删除并返回指定位置的元素](#1. pop(索引) —— 删除并返回指定位置的元素)
[2.remove(值) ------ 删除第一个匹配的值](#2.remove(值) —— 删除第一个匹配的值)
[3.clear() ------ 清空整个列表](#3.clear() —— 清空整个列表)
[4. del 语句 ------ 删除切片或整个变量](#4. del 语句 —— 删除切片或整个变量)
[2.复制列表:浅拷贝 vs 深拷贝](#2.复制列表:浅拷贝 vs 深拷贝)
[3. 列表作为栈和队列](#3. 列表作为栈和队列)
[4.用 enumerate() 同时获取索引和值](#4.用 enumerate() 同时获取索引和值)
[5. 列表推导式的高级用法](#5. 列表推导式的高级用法)
[6. 将列表当作"参数包" ------ * 解包](#6. 将列表当作“参数包” —— * 解包)
[7. 常见陷阱与避坑指南](#7. 常见陷阱与避坑指南)
开篇:什么是列表?
想象你有一个购物清单:苹果、牛奶、面包、鸡蛋。你需要一个地方按顺序记下这些东西,随时可以添加新物品、划掉已买的、查看是否还有某样东西。在 Python 中,**列表(list)**就是这样的"超级购物清单"。
列表是一种有序、可变、可包含任意类型元素 的容器。用方括号 [] 表示,元素之间用逗号分隔。
shopping_list = ["苹果", "牛奶", "面包", "鸡蛋"]
可以在列表中放数字、字符串、甚至另一个列表......几乎任何东西。
1.创建列表
1.直接使用方括号
最常见的方式,直接将元素写在 [] 中:
fruits = ["苹果", "香蕉", "橙子"] # 字符串列表
numbers = [1, 2, 3, 4, 5] # 整数列表
mixed = [42, "hello", 3.14, True] # 混合类型列表(完全合法)
empty = [] # 空列表
-
列表的元素可以是任何类型:数字、字符串、小数、布尔值,甚至另一个列表。
-
同一个列表里可以混装不同类型,比如
[42, "hello", 3.14, True]。
小贴士 :列表的名字通常用复数形式(如 fruits、numbers),暗示它包含多个值。
2.使用 list() 构造器
list() 就像一个"转换器",可以把其他序列变成列表。
可以从其他可迭代对象(如字符串、元组、range)创建列表:
# 把字符串拆成一个个字符
chars = list("abc")
print(chars) # ['a', 'b', 'c']
# 把 range 对象变成列表
numbers = list(range(5))
print(numbers) # [0, 1, 2, 3, 4]
# 从元组(另一种不可变的序列)创建
tup = (1, 2, 3)
lst = list(tup)
print(lst) # [1, 2, 3]
# 创建空列表的另一种方式
empty = list()
print(empty) # []
Python 中的元组(tuple) 是一种不可变的序列,可以存储任意类型的元素(混合类型),用圆括号表示
3.列表推导式 ------ 一行代码批量生产
假设你想生成 0 到 9 的平方数列表。传统方式要写三四行循环,而列表推导式只需要一行:
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我们来拆解这行代码:
for x in range(10):循环变量x依次取 0~9。
x**2:对每个x计算平方。 **幂运算符
[...]:把这些结果收集起来组成列表。
还可以加上条件过滤,用之前的一些知识,比如只保留偶数的平方:
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
4.用乘法 * 快速初始化
如果需要一个重复元素的列表,可以用"乘号":
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
stars = ["*"] * 3
print(stars) # ['*', '*', '*']
重要警告:
如果列表里装的是可变对象(比如另一个列表),乘法会复制引用,导致意想不到的后果。
matrix = [[0] * 3] * 2 # 看起来像是两行三列的矩阵
print(matrix) # [[0, 0, 0], [0, 0, 0]]
matrix[0][0] = 1
print(matrix) # [[1, 0, 0], [1, 0, 0]] ------ 第一列的两个元素都变了!
这是因为 [0]*3 先创建了一个单行列表,然后 *2 复制了它的引用,导致两行指向同一块内存。
正确创建二维列表应该用列表推导式:
matrix = [[0] * 3 for _ in range(2)] # 生成两个独立的小列表
2.查找列表
创建好列表后,你需要知道怎么查看里面的内容。列表是有序的,每个元素都有一个位置编号,我们称之为索引。
1.索引:从 0 开始的位置编号
生活中我们数数一般从 1 开始,但 Python(以及绝大多数编程语言)从 0 开始。所以第一个元素的索引是 0,第二个是 1,第三个是 2......
其实跟C/C++下标一样
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
索引: 0 1 2 3
要取某个位置的元素,用 列表名[索引]:
print(fruits[0]) # 苹果
print(fruits[2]) # 橙子
如果你尝试访问一个不存在的索引(比如 fruits[10]),Python 会报错:IndexError: list index out of range。
2.负索引:从尾巴开始数
Python 有个非常贴心的设计:你可以用负整数从末尾开始数。-1 代表最后一个,-2 代表倒数第二个,依此类推。
print(fruits[-1]) # 葡萄
print(fruits[-2]) # 橙子
这比用 fruits[len(fruits)-1] 简洁多了。当你不知道列表有多长但想取最后一个时,-1 永远正确。
3. 切片:取一段子列表
之前切片也讲过一点
如果你想取连续的一段元素,比如第 1 个到第 3 个(注意索引规则),可以用切片 语法:[开始索引:结束索引]。注意:结束索引不包含在内。
nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4]) # [1, 2, 3] ------ 取索引 1、2、3,不含索引 4
切片还可以省略开始或结束:
[:3]表示从开头到索引 3(不含 3)
[3:]表示从索引 3 到末尾
[:]表示整个列表的副本(后面会详细讲)
还可以加 步长:
print(nums[::2]) # [0, 2, 4] 每隔一个取一个
print(nums[::-1]) # [5, 4, 3, 2, 1, 0] 反转列表
切片不会越界报错 :nums[1:100] 会安全地返回从索引 1 到末尾的所有元素,而不会崩溃。这是一个很贴心的特性。
4.查找元素的索引:index()
如果你知道元素的值,想找到它第一次出现的位置,用 index() 方法。
colors = ["红", "绿", "蓝", "绿"]
pos = colors.index("绿")
print(pos) # 1(第一次出现的位置)
如果列表中有多个相同元素,index() 只返回第一个。
如果元素不存在 ,index() 会直接抛出 ValueError,程序会终止。所以通常先判断一下:
if "黄" in colors:
print(colors.index("黄"))
else:
print("没有黄色")
5. 统计出现次数:count()
想知道某个值在列表中出现了几次,用 count():
colors = ["红", "绿", "蓝", "绿"]
print(colors.count("绿")) # 2
print(colors.count("黑")) # 0(不存在的返回 0,不会报错)
6. 判断是否存在:in 与 not in
这是最常用的成员检查,返回 True 或 False。
fruits = ["苹果", "香蕉"]
print("苹果" in fruits) # True
print("芒果" not in fruits) # True
in 是符合直觉的自然语言,推荐使用。
7.获取列表长度:len()
len() 是 Python 内置函数,返回列表中有多少个元素。
print(len(fruits)) # 2
3.修改列表
让数据动起来
列表最大的魅力在于它是可变的。你可以改变里面的内容,可以增加,可以删除。
1. 通过索引修改元素
直接赋值即可:
fruits = ["苹果", "香蕉", "橙子"]
fruits[1] = "草莓"
print(fruits) # ['苹果', '草莓', '橙子']
这就像你把购物清单上的"香蕉"划掉,改写成"草莓"。
2. 在末尾追加:append()
append() 在列表的最后面添加一个新元素。
fruits.append("芒果")
print(fruits) # ['苹果', '草莓', '橙子', '芒果']
3. 在中间插入:insert()
insert(索引, 值) 可以在任意位置插入。插入后,该位置及后面的元素都会向后移动一位。
fruits.insert(1, "菠萝")
print(fruits) # ['苹果', '菠萝', '草莓', '橙子', '芒果']
4. 扩展列表:extend() 与 +=
如果你有另一个列表(或任何可迭代对象)想要全部加进来,用 extend()。
more = ["石榴", "桃子"]
fruits.extend(more)
print(fruits) # ['苹果', '菠萝', '草莓', '橙子', '芒果', '石榴', '桃子']
也可以写成 fruits += more(与 extend 效果相同)。
more = ["石榴", "桃子"]
fruits+=more
print(fruits) # ['苹果', '菠萝', '草莓', '橙子', '芒果', '石榴', '桃子']
区分 append 和 extend:
lst = [1, 2]
lst.append([3, 4]) # 把整个 [3,4] 当成一个元素加进去
print(lst) # [1, 2, [3, 4]]
lst2 = [1, 2]
lst2.extend([3, 4]) # 把 3 和 4 分别加入
print(lst2) # [1, 2, 3, 4]
append 是"整箱放进去",extend 是"拆箱后一个个放"。
5. 修改切片:一套强大的批量替换
你可以用切片同时替换多个元素,甚至替换成不同数量的元素:
nums = [0, 1, 2, 3, 4]
nums[1:3] = [100, 200, 300] # 替换索引 1 和 2 的位置,放入三个新元素
print(nums) # [0, 100, 200, 300, 3, 4]
删除一段元素也简单:赋值为空列表 []:
nums[2:5] = [] # 删除索引 2~4 的元素
print(nums) # [0, 100, 4]
6. 其他修改方式:排序与反转
-
reverse():原地反转顺序(不返回新列表)nums = [1, 2, 3]
nums.reverse()
print(nums) # [3, 2, 1] -
sort():原地排序(默认升序)nums = [3, 1, 4, 2]
nums.sort()
print(nums) # [1, 2, 3, 4]
如果想降序:nums.sort(reverse=True)。
nums.sort(reverse=True) 中的 reverse 是一个关键字参数(命名参数),它需要接收一个布尔值
注意:sort() 和 reverse() 都是修改原列表,不返回新列表。如果你想保留原列表,用 sorted() 和 reversed() 函数。
original = [3, 1, 4]
new_sorted = sorted(original) # 不改变 original
print(original) # [3, 1, 4]
print(new_sorted) # [1, 3, 4]
4.删除列表元素
删除元素有好几种方式,可以根据情况来进行选择。
1. pop(索引) ------ 删除并返回指定位置的元素
pop() 就像从一叠纸牌中抽出一张:你既删除了它,还能拿到它。
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
removed = fruits.pop(1) # 删除索引 1(香蕉)
print(removed) # 香蕉
print(fruits) # ['苹果', '橙子', '葡萄']
如果不给参数,pop() 删除并返回最后一个元素
last = fruits.pop()
print(last) # 葡萄
print(fruits) # ['苹果', '橙子']
何时用 pop():你需要用到被删除的值时。
2.remove(值) ------ 删除第一个匹配的值
如果你不知道索引,只知道要删除哪个值,用 remove()。
fruits = ["苹果", "香蕉", "橙子", "香蕉"]
fruits.remove("香蕉") # 删除第一次出现的香蕉
print(fruits) # ['苹果', '橙子', '香蕉'] (还剩一个香蕉)
如果值不存在,会抛出 ValueError。建议先检查:
if "芒果" in fruits:
fruits.remove("芒果")
注意 :remove() 只删除第一个匹配项。要删除所有匹配,需要循环或列表推导式(后面会讲)。
3.clear() ------ 清空整个列表
fruits.clear()
print(fruits) # []
清空后,列表变量还在(空列表),只是里面没东西了。
4. del 语句 ------ 删除切片或整个变量
del 不是方法,而是 Python 语句,可以删除列表的某一段,或者完全删除变量。
删除切片
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
del fruits[1:3] # 删除索引 1 和 2
print(fruits) # ['苹果', '葡萄']
删除整个变量
del fruits
# print(fruits) # NameError: name 'fruits' is not defined
5.进阶扩展
Python 列表与 C/C++ 数组的底层实现 有相似之处,但在使用层面差异很大。
1.底层实现
-
Python 列表 本质上是一个动态数组 ,内部连续存储指向
PyObject的指针。它支持 O(1) 索引,自动扩容(预留空间)。 -
C/C++ 数组 (如
int arr[10])也是连续内存块,存储具体值或指针(如果是指针数组)。
使用层面的区别
| 特性 | Python 列表 | C/C++ 数组 |
|---|---|---|
| 元素类型 | 可存储任意混合类型(其实是指针,指向不同对象) | 所有元素类型必须相同 |
| 大小 | 动态可变(append, pop 等) |
固定大小,创建后不可变 |
| 内存管理 | 自动管理(垃圾回收、内存分配) | 手动分配/释放(栈上自动,堆上需free) |
| 索引检查 | 自动进行边界检查,越界抛出 IndexError |
不检查边界,越界是未定义行为 |
| 性能 | 稍慢(因为存储的是指针,多一层间接访问;动态扩容有开销) | 更快(直接访问值,无额外间接) |
| 嵌套 | 任意层次的嵌套(列表里套列表) | 多维数组(每个维度大小固定) |
2.复制列表:浅拷贝 vs 深拷贝
直接赋值不会复制列表,只是给同一块内存贴了个新标签。修改新变量会同时影响原变量。
a = [1, 2, 3]
b = a # b 和 a 指向同一个列表
b[0] = 99
print(a) # [99, 2, 3] ------ a 也被改了
如果你想要一个独立副本,可以用以下方式:
b = a.copy()
b = a[:]
b = list(a)
但这些方法都是浅拷贝:如果列表内部还有子列表(嵌套),子列表仍然共享。
a = [1, [2, 3]]
b = a.copy()
b[1][0] = 99
print(a) # [1, [99, 3]] ------ 内部列表被影响!
要彻底独立,需要用深拷贝:
import copy
a = [1, [2, 3]]
b = copy.deepcopy(a)
b[1][0] = 99
print(a) # [1, [2, 3]] 原列表完好无损
copy是 Python 标准库提供的一个模块。
deepcopy是copy模块里预定义的函数,专门用来执行深拷贝操作。调用方式
copy.deepcopy(a)表示:从copy模块中取出deepcopy这个函数,然后把a作为参数传进去。类似的,
copy.copy()是浅拷贝函数。
3. 列表作为栈和队列
-
栈(Last-In-First-Out) :后进先出,像叠盘子。用
append()压入,用pop()弹出。 -
队列(First-In-First-Out) :先进先出,像排队。可以用
append()入队,pop(0)出队,但pop(0)效率低。更好的做法是用collections.deque。
4.用 enumerate() 同时获取索引和值
在循环中既想要元素值,又想要它的索引,使用 enumerate():
fruits = ["苹果", "香蕉", "橙子"]
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 输出:
# 0: 苹果
# 1: 香蕉
# 2: 橙子
5. 列表推导式的高级用法
可以嵌套循环、多重条件:
# 生成 (x,y) 坐标对
coords = [(x, y) for x in range(3) for y in range(2)]
print(coords) # [(0,0), (0,1), (1,0), (1,1), (2,0), (2,1)]
# 带条件的嵌套
pairs = [(x, y) for x in range(5) for y in range(5) if x != y]
6. 将列表当作"参数包" ------ * 解包
可以用 * 将列表拆解成多个参数传给函数:
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add(*nums)) # 6 等同于 add(1,2,3)
7. 常见陷阱与避坑指南
| 陷阱 | 说明 | 正确做法 |
|---|---|---|
| 索引越界 | lst[100] 会抛出 IndexError |
先 if len(lst) > 100: 或用切片(切片不报错) |
| 遍历时删除元素 | 跳过元素或引发错误 | 遍历副本 for x in lst[:]: 或者用列表推导式过滤 |
| 浅拷贝导致内部列表共享 | 修改嵌套列表影响原对象 | 使用 copy.deepcopy() |
append vs extend 混淆 |
误将列表整体添加而不是拆开 | 需要分别添加元素用 extend 或 += |
忘记 sorted 不改变原列表 |
sorted(lst) 不修改原列表,需赋值 |
lst = sorted(lst) 或使用 lst.sort() |
用 = 而不是 == 比较 |
if lst = [1,2]: 语法错误 |
if lst == [1,2]: |
感谢你的观看,期待我们下次再见!