列表基础
列表(list)是 Python 中最常用的数据结构。它是一个有序、可变、可重复的序列,可以容纳任意类型的对象——整数、字符串、甚至其他列表。列表用方括号 [] 表示,元素之间用逗号分隔。
创建列表
# 空列表
empty = []
# 包含元素的列表
fruits = ["apple", "banana", "cherry"]
mixed = [1, "hello", 3.14, [1, 2]] # 类型可以混合
# 用 list() 构造函数
chars = list("abc") # ['a', 'b', 'c']
nums = list(range(5)) # [0, 1, 2, 3, 4]
索引访问
列表元素按顺序编号,从 0 开始。也可以用负数索引从末尾访问:
nums = [10, 20, 30, 40, 50]
print nums[0] # 10,第一个元素
print nums[2] # 30,第三个元素
print nums[-1] # 50,最后一个元素
print nums[-2] # 40,倒数第二个
索引越界会抛出 IndexError:
print nums[10] # IndexError: list index out of range
print nums[-10] # IndexError(如果列表没有 10 个元素)
切片
切片用 [start:stop:step] 语法,返回一个新列表:
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print nums[2:5] # [2, 3, 4],左闭右开
print nums[:3] # [0, 1, 2],从头开始
print nums[7:] # [7, 8, 9],到末尾
print nums[::2] # [0, 2, 4, 6, 8],每隔一个
print nums[::-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0],反转
print nums[5:1:-1] # [5, 4, 3, 2],倒序切片
切片不会越界报错,而是自动截断到有效范围:
print nums[5:100] # [5, 6, 7, 8, 9],不会报错
print nums[100:200] # [],空列表
列表是可变的
与字符串和元组不同,列表可以原地修改:
nums = [1, 2, 3]
nums[0] = 100
print nums # [100, 2, 3]
也可以通过切片赋值批量替换:
nums = [1, 2, 3, 4, 5]
nums[1:3] = [20, 30]
print nums # [1, 20, 30, 4, 5]
# 甚至可以替换不同数量的元素
nums[1:3] = [200, 300, 400]
print nums # [1, 200, 300, 400, 4, 5]
# 删除一段元素
nums[1:4] = []
print nums # [1, 4, 5]
列表的内存行为
列表存储的是对象的引用,而非对象本身。这意味着同一个对象可以被多个列表共享:
a = [1, 2, 3]
b = a # b 和 a 指向同一个列表
b[0] = 100
print a # [100, 2, 3] —— a 也被改了!
如果需要独立的副本,用切片或 list():
a = [1, 2, 3]
b = a[:] # 浅拷贝
b[0] = 100
print a # [1, 2, 3] —— a 不受影响
c = list(a) # 同样是浅拷贝
c[0] = 200
print a # [1, 2, 3]
注意"浅拷贝"只复制一层。如果列表包含子列表,子列表仍然共享:
a = [[1, 2], [3, 4]]
b = a[:]
b[0][0] = 100
print a # [[100, 2], [3, 4]] —— 子列表被共享了!
需要完全独立的副本时,用 copy.deepcopy:
import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)
b[0][0] = 100
print a # [[1, 2], [3, 4]]
列表作为栈
列表的 append() 和 pop() 方法让它天然适合实现栈(后进先出):
stack = []
stack.append(1) # 入栈
stack.append(2)
stack.append(3)
print stack # [1, 2, 3]
print stack.pop() # 3,出栈
print stack.pop() # 2
print stack # [1]
列表作为队列
列表也可以模拟队列(先进先出),但 pop(0) 效率低——它需要将后面所有元素前移,时间复杂度 O(n):
queue = []
queue.append("a") # 入队
queue.append("b")
queue.append("c")
print queue.pop(0) # "a",出队 —— 效率低!
对于真正的队列,应该使用 collections.deque,它的两端添加/弹出都是 O(1)。