一. 列表简介
Python中的列表(list)是一种有序、可变、可重复元素的集合数据类型。它是Python中最常用和最灵活的数据结构之一,可以存储不同类型的数据元素。
🚀列表的基本特性:
有序性:元素按照插入顺序排列,可以通过索引访问
可变性:创建后可以修改、添加或删除元素
动态大小:列表大小可以自动调整,无需预先指定容量
异构性:可以同时包含不同类型的数据
二. 创建列表
💡基本创建方式
①. 使用方括号:empty_list = [] # 空列表numbers = [1, 2, 3, 4, 5] # 整数列表mixed = [1, "hello", 3.14, True] # 混合类型列表②. 使用list()构造函数:list_from_range = list(range(5)) # [0, 1, 2, 3, 4]list_from_string = list("Python") # ['P', 'y', 't', 'h', 'o', 'n']③. 使用列表推导式:squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
三. 访问列表元素
📈索引关系:
索引: 0 1 2 3 4列表: [10, 20, 30, 40, 50]负索引: -5 -4 -3 -2 -1
📊索引访问
fruits = ["apple", "banana", "cherry", "date", "elderberry"]print(fruits[0]) # 输出: apple (正向索引,从0开始)print(fruits[2]) # 输出: cherryprint(fruits[-1]) # 输出: elderberry (负向索引,-1表示最后一个元素)print(fruits[-2]) # 输出: date
⚡️切片操作(左闭右开,不改变原列表)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]print(numbers[2:5]) # 输出: [2, 3, 4] (索引2到5,不包含5)print(numbers[:3]) # 输出: [0, 1, 2] (从开始到索引3)print(numbers[5:]) # 输出: [5, 6, 7, 8, 9] (从索引5到末尾)print(numbers[::2]) # 输出: [0, 2, 4, 6, 8] (步长为2)print(numbers[::-1]) # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (反转列表)
四. 修改列表
列表是可变类型,可以直接修改元素。
🔍修改单个元素
colors = ["red", "green", "blue"]colors[1] = "yellow" # 将索引1的元素从"green"改为"yellow"print(colors) # 输出: ['red', 'yellow', 'blue']
⚙️修改切片
numbers = [1, 2, 3, 4, 5]numbers[1:4] = [20, 30, 40] # 替换索引1到4的元素print(numbers) # 输出: [1, 20, 30, 40, 5]
五. 常用列表方法
📈添加元素
fruits = ["apple", "banana"]①. append() - 在末尾添加单个元素fruits.append("cherry")print(fruits) # 输出: ['apple', 'banana', 'cherry']②. extend() - 添加多个元素(扩展列表)fruits.extend(["date", "elderberry"])print(fruits) # 输出: ['apple', 'banana', 'cherry', 'date', 'elderberry']③. insert() - 在指定位置插入元素fruits.insert(1, "grape")print(fruits) # 输出: ['apple', 'grape', 'banana', 'cherry', 'date', 'elderberry']
💻删除元素
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]①. remove() - 删除第一个匹配的元素(如果列表里有两5只删除匹配的第一个5)numbers.remove(5)print(numbers) # 输出: [1, 2, 3, 4, 6, 7, 8, 9]②. pop() - 删除并返回指定位置的元素(默认最后一个)last = numbers.pop()print(last) # 输出: 9print(numbers) # 输出: [1, 2, 3, 4, 6, 7, 8]second = numbers.pop(1)print(second) # 输出: 2print(numbers) # 输出: [1, 3, 4, 6, 7, 8]③. del语句 - 删除指定位置的元素或切片del numbers[2] # 删除索引2的元素print(numbers) # 输出: [1, 3, 6, 7, 8]del numbers[1:3] # 删除索引1到3的元素print(numbers) # 输出: [1, 7, 8]④. clear() - 清空列表numbers.clear()print(numbers) # 输出: []
使用倒序索引删除numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]# 从后往前删除,这样删除元素不会影响前面元素的索引for i in range(len(numbers)-1, -1, -1): # 从最后一个索引到第一个索引 if numbers[i] % 2 == 0: numbers.remove(numbers[i]) # 或者用 del numbers[i]print("倒序删除结果:", numbers) # 输出: [1, 3, 5, 7, 9]
🎯查找和计数
letters = ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c']①. index() - 返回第一个匹配元素的索引print(letters.index('c')) # 输出: 2print(letters.index('b', 3)) # 输出: 6 (从索引3开始查找)②. count() - 统计元素出现的次数print(letters.count('a')) # 输出: 2print(letters.count('z')) # 输出: 0 (不存在)③. in运算符 - 检查元素是否存在print('d' in letters) # 输出: Trueprint('z' in letters) # 输出: False
⚙️排序和反转
①. sort() - 原地排序numbers = [5, 2, 8, 1, 9]numbers.sort()print(numbers) # 输出: [1, 2, 5, 8, 9]numbers.sort(reverse=True)print(numbers) # 输出: [9, 8, 5, 2, 1]②. sorted() - 返回新排序列表,不修改原列表numbers = [5, 2, 8, 1, 9]sorted_numbers = sorted(numbers)print(numbers) # 输出: [5, 2, 8, 1, 9] (原列表不变)print(sorted_numbers) # 输出: [1, 2, 5, 8, 9] (新排序列表)③. reverse() - 原地反转列表numbers = [1, 2, 3, 4, 5]numbers.reverse()print(numbers) # 输出: [5, 4, 3, 2, 1]
六. 列表推导式
1.定义:.
使用简易方法,将可迭代对象转换为列表。
2.语法:
变量=[表达式 for 变量 in 可迭代对象]
变量=[表达式 for 变量 in 可迭代对象 if 条件]
3.说明:
如果if真值表达式的布尔值为False,则可迭代对象
①. 基本形式squares = [x**2 for x in range(10)]print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]②. 带条件的列表推导式even_squares = [x**2 for x in range(10) if x % 2 == 0]print(even_squares) # 输出: [0, 4, 16, 36, 64]③. 多个循环pairs = [(x, y) for x in range(3) for y in range(2)]print(pairs) # 输出: [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]④. 嵌套列表推导式matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]flattened = [num for row in matrix for num in row]print(flattened) # 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
💡使用条件: 表达式和 if条件不太复杂可以使用,如果过于复杂强行使用列表推导式反而不适合
七. 列表与循环
1、正向循环语法:
for 索引名 in range(len(列表名)):
# 循环体
⚡️参数解释:range(len(列表名)):生成从0到len(列表名)-1的整数序列
默认参数:range(start=0, stop=len(列表名), step=1)
循环次数:列表长度次,每次索引递增1
2、反向循环语法:
for 索引名 in range(len(列表名)-1, -1, -1):
# 循环体
🔍参数解释:
len(列表名)-1:起始索引,列表最后一个元素的索引
-1:结束索引,循环到索引0为止(不包含-1)
-1:步长,每次减1,反向遍历
示例:fruits = ["apple", "banana", "cherry", "date", "elderberry"]print("=== 正向遍历 ===")for i in range(len(fruits)): print(f"索引 {i}: {fruits[i]}")print("\n=== 反向遍历 ===")for i in range(len(fruits)-1, -1, -1): print(f"索引 {i}: {fruits[i]}")# 输出:# === 反向遍历 ===# 索引 4: elderberry# 索引 3: date# 索引 2: cherry# 索引 1: banana# 索引 0: apple
遍历列表元素fruits = ["apple", "banana", "cherry"]①. 直接遍历元素for fruit in fruits: print(f"I like {fruit}")②. 遍历索引和元素for i, fruit in enumerate(fruits): print(f"Index {i}: {fruit}")③. 同时遍历多个列表names = ["Alice", "Bob", "Charlie"]scores = [85, 92, 78]for name, score in zip(names, scores): print(f"{name}: {score}")④. 列表作为堆栈使用(后进先出)stack = []stack.append(1) # 入栈stack.append(2)stack.append(3)print(stack.pop()) # 出栈,输出: 3print(stack) # 输出: [1, 2]⑤. 列表作为队列使用(先进先出)from collections import dequequeue = deque(["Alice", "Bob", "Charlie"])queue.append("David") # 入队print(queue.popleft()) # 出队,输出: Aliceprint(queue) # 输出: deque(['Bob', 'Charlie', 'David'])
八. 列表操作注意事项
⚙️浅拷贝与深拷贝
①. 浅拷贝问题original = [[1, 2], [3, 4]]shallow_copy = original.copy() # 或 original[:] 或 list(original)shallow_copy[0][0] = 99print(original) # 输出: [[99, 2], [3, 4]] (原列表也被修改了!)print(shallow_copy) # 输出: [[99, 2], [3, 4]]②. 深拷贝解决方案import copyoriginal = [[1, 2], [3, 4]]deep_copy = copy.deepcopy(original)deep_copy[0][0] = 99print(original) # 输出: [[1, 2], [3, 4]] (原列表不变)print(deep_copy) # 输出: [[99, 2], [3, 4]]
🎯深拷贝就是将原来列表的所有数据彻底复制一份,原来列表的数据无论如何修改都不会影响深拷贝后的列表的数据。
📊列表比较
list1 = [1, 2, 3]list2 = [1, 2, 3]list3 = [1, 2, 4]print(list1 == list2) # 输出: True (值相等)print(list1 == list3) # 输出: Falseprint(list1 is list2) # 输出: False (不是同一个对象)
九. 性能考虑
1、时间复杂度:
索引访问:O(1)
末尾添加/删除:O(1)
在开头或中间插入/删除:O(n)
查找元素:O(n)
2、内存效率:列表会预先分配额外空间以支持快速追加操作
3、替代方案:
大量插入/删除操作:考虑使用 collections.deque
频繁查找操作:考虑使用 set 或 dict
数值计算:考虑使用 NumPy 数组
O(1) 是常数时间复杂度的表示,意味着算法的执行时间不随输入数据规模的变化而变化。无论输入数据有多大,执行时间都是固定的、恒定的。
直观理解:
O(1):执行时间恒定,与数据量无关
O(n):执行时间随数据量线性增长
O(n²):执行时间随数据量平方增长
总结:
需要新列表? 用切片[:]、copy()或列表推导式
频繁头部插入? 考虑collections.deque(O(1) vs 列表O(n))
大数据量过滤? 优先用生成器表达式节省内存:(x for x in big_list if condition)
调试技巧:用id(lst)检查是否为同一对象
性能提示:append比insert(0, x)快100倍以上(避免头部操作)
修改操作多为原地生效(返回None)
切片/推导式生成新列表,不影响原数据
深浅拷贝根据嵌套结构谨慎选择