Python基础指南之列表list的创建与基本操作详解
一、开篇:Python中最忙的数据类型
前面几篇文章我们把字符串(str)和字节(bytes)讲透了。今天终于迎来Python中使用频率最高的容器类型——列表(list)。
如果你问我Python中哪个数据结构用得最多,我会毫不犹豫地回答:列表。无论是存储一组用户数据、收集爬虫抓取的结果、缓存中间计算结果,还是作为函数的可变参数——列表无处不在。它是Python的"瑞士军刀",灵活、强大、易用。
列表是Python内置的序列类型之一(另外还有元组、字符串、字节串等)。它的核心特征:有序、可变、可重复、可包含任意类型的元素。这篇我们先从创建和基本操作讲起,下一篇深入索引和切片。
二、列表是什么——三个维度理解列表
2.1 列表的四个核心特征
# 特征一:有序——元素有固定的位置,按插入顺序排列
fruits = ['苹果', '香蕉', '橘子']
print(fruits[0]) # 苹果(第一个元素)
print(fruits[1]) # 香蕉(第二个元素)
# 特征二:可变——可以增删改元素
fruits[1] = '葡萄'
print(fruits) # ['苹果', '葡萄', '橘子']
fruits.append('西瓜')
print(fruits) # ['苹果', '葡萄', '橘子', '西瓜']
# 特征三:可重复——同一个值可以出现多次
scores = [85, 90, 85, 95, 85]
print(scores.count(85)) # 3
# 特征四:可包含任意类型——混合存放不同类型的数据
mixed = [42, 'hello', 3.14, True, None, [1, 2], {'key': 'value'}]
print(mixed)
2.2 列表的内存模型
# 列表存储的是对象的"引用",不是对象本身 # 这解释了为什么列表可以包含不同类型的元素 a = [1, 2, 3] b = [1, 2, 3] # a和b是两个不同的列表对象(虽然内容相同) print(a == b) # True(内容相等) print(a is b) # False(不是同一个对象) # 列表中的元素是对其他对象的引用 x = 'hello' y = 42 z = [1, 2] lst = [x, y, z] # lst存储了对x、y、z三个对象的引用 print(lst) # ['hello', 42, [1, 2]] # 修改变量不影响列表(因为列表存的是引用,不是变量本身) x = 'world' print(lst) # ['hello', 42, [1, 2]] (lst[0]仍然指向原来的'hello'对象) # 但如果修改可变对象的内容,列表中会反映出来 z.append(3) print(lst) # ['hello', 42, [1, 2, 3]] (lst[2]指向的列表被修改了)
理解列表存储引用这一点非常关键。很多"莫名其妙"的bug就源自忘记了这个事实——特别是嵌套列表的复制。
三、创建列表的七种方式
3.1 字面量(最常用)
# 空列表 empty = [] print(empty) # [] # 包含元素的列表 numbers = [1, 2, 3, 4, 5] fruits = ['苹果', '香蕉', '橘子'] mixed = [1, 'hello', 3.14, True] # 嵌套列表 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(matrix[1][2]) # 6(第二行第三列)
3.2 list() 构造函数
# 从可迭代对象创建列表
print(list('hello')) # ['h', 'e', 'l', 'l', 'o'](将字符串拆为字符列表)
print(list((1, 2, 3))) # [1, 2, 3](元组→列表)
print(list(range(5))) # [0, 1, 2, 3, 4]
print(list({'a': 1, 'b': 2})) # ['a', 'b'](字典的键)
print(list({'a': 1, 'b': 2}.values())) # [1, 2](字典的值)
# 没有参数时创建空列表
empty = list()
print(empty) # []
3.3 列表推导式(最Pythonic的方式)
# 基本推导式
squares = [x ** 2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的推导式
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 带转换的推导式
words = ['hello', 'world', 'python']
upper_words = [w.upper() for w in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']
# 嵌套循环的推导式
pairs = [(x, y) for x in range(3) for y in range(3)]
print(pairs)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 实际场景:提取字典列表中某个字段
users = [
{'name': '小明', 'age': 25},
{'name': '小红', 'age': 23},
{'name': '小刚', 'age': 26},
]
names = [user['name'] for user in users]
print(names) # ['小明', '小红', '小刚']
3.4 重复创建
# 用乘法创建重复元素的列表 zeros = [0] * 5 print(zeros) # [0, 0, 0, 0, 0] repeated = ['hello'] * 3 print(repeated) # ['hello', 'hello', 'hello'] # ⚠️ 重要陷阱!嵌套列表的乘法 # 下面的写法有bug! matrix_bug = [[0] * 3] * 3 print(matrix_bug) # [[0, 0, 0], [0, 0, 0], [0, 0, 0]] matrix_bug[0][0] = 1 print(matrix_bug) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] # 三行都变了!因为乘法复制的是引用,三行指向同一个内部列表 # ✅ 正确的嵌套列表创建方式 matrix_good = [[0] * 3 for _ in range(3)] matrix_good[0][0] = 1 print(matrix_good) # [[1, 0, 0], [0, 0, 0], [0, 0, 0]] # 每次循环创建一个新的内部列表
3.5 split() 方法创建
# 从字符串分割创建列表
csv_line = '小明,25,北京,工程师'
fields = csv_line.split(',')
print(fields) # ['小明', '25', '北京', '工程师']
# 多行文本→行列表
text = '第一行\n第二行\n第三行'
lines = text.splitlines()
print(lines) # ['第一行', '第二行', '第三行']
# 默认按空白分割
words = 'Python Java Go Rust'.split()
print(words) # ['Python', 'Java', 'Go', 'Rust']
3.6 range() 创建数字列表
# 等差数列 nums = list(range(10)) print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] nums2 = list(range(5, 15)) print(nums2) # [5, 6, 7, 8, 9, 10, 11, 12, 13, 14] nums3 = list(range(0, 101, 10)) print(nums3) # [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] # 倒序 nums4 = list(range(10, 0, -1)) print(nums4) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
3.7 从其他数据源创建
# 从文件读取的所有行
with open('test.txt', 'r', encoding='utf-8') as f:
lines = f.readlines() # 每行作为一个元素的列表
# 从生成器
gen = (x ** 2 for x in range(5))
lst = list(gen)
print(lst) # [0, 1, 4, 9, 16]
# 从JSON数据
import json
json_str = '[{"name": "小明"}, {"name": "小红"}]'
data = json.loads(json_str)
print(data) # [{'name': '小明'}, {'name': '小红'}]
# 从遍历的结果收集
result = []
for i in range(10):
if i % 3 == 0 or i % 5 == 0:
result.append(i)
print(result) # [0, 3, 5, 6, 9]
四、列表的基本操作
4.1 索引访问
fruits = ['苹果', '香蕉', '橘子', '葡萄', '西瓜']
# 正向索引(从0开始)
print(fruits[0]) # 苹果
print(fruits[1]) # 香蕉
print(fruits[4]) # 西瓜
# 负向索引(从-1开始,-1是最后一个)
print(fruits[-1]) # 西瓜
print(fruits[-2]) # 葡萄
print(fruits[-5]) # 苹果
# 索引越界
# print(fruits[5]) # IndexError: list index out of range
# print(fruits[-6]) # IndexError: list index out of range
# 安全访问(避免索引错误)
def safe_get(lst, index, default=None):
"""安全地从列表中获取元素"""
try:
return lst[index]
except IndexError:
return default
print(safe_get(fruits, 10, '未知')) # 未知
4.2 切片操作(预览)
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 基本切片 [start:stop:step] print(nums[2:7]) # [2, 3, 4, 5, 6](索引2到6) print(nums[:5]) # [0, 1, 2, 3, 4](从头到索引4) print(nums[5:]) # [5, 6, 7, 8, 9](从索引5到末尾) print(nums[::2]) # [0, 2, 4, 6, 8](每隔一个取一个) print(nums[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0](反转列表) # 切片不会索引越界——这是它和索引访问的重要区别 print(nums[5:100]) # [5, 6, 7, 8, 9](自动截断) print(nums[100:]) # [](空列表)
切片是下一篇的重头戏,这里先给你一个预览。掌握好切片是成为Python高手的必经之路。
4.3 遍历列表
fruits = ['苹果', '香蕉', '橘子']
# 方式一:直接遍历元素
for fruit in fruits:
print(fruit)
# 方式二:用索引遍历
for i in range(len(fruits)):
print(f'第{i}个:{fruits[i]}')
# 方式三:用enumerate()同时获取索引和元素
for i, fruit in enumerate(fruits):
print(f'第{i}个:{fruit}')
# 方式四:用enumerate指定起始索引
for i, fruit in enumerate(fruits, start=1):
print(f'第{i}个:{fruit}')
# 第1个:苹果
# 第2个:香蕉
# 第3个:橘子
# 方式五:反向遍历
for fruit in reversed(fruits):
print(fruit)
# 方式六:排序后遍历
for fruit in sorted(fruits):
print(fruit)
# 同时遍历多个列表
names = ['小明', '小红', '小刚']
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f'{name}:{score}分')
4.4 列表的运算
# 连接(+)——创建新列表
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c) # [1, 2, 3, 4, 5, 6]
print(a) # [1, 2, 3](a没变)
print(b) # [4, 5, 6](b没变)
# 重复(*)——创建新列表
d = [0] * 5
print(d) # [0, 0, 0, 0, 0]
e = [1, 2] * 3
print(e) # [1, 2, 1, 2, 1, 2]
# 成员检查(in / not in)
fruits = ['苹果', '香蕉', '橘子']
print('苹果' in fruits) # True
print('西瓜' in fruits) # False
print('西瓜' not in fruits) # True
# 长度
print(len(fruits)) # 3
# 最大值/最小值(元素必须可比较)
nums = [5, 2, 8, 1, 9, 3]
print(min(nums)) # 1
print(max(nums)) # 9
print(sum(nums)) # 28
# 对字符串列表
words = ['apple', 'banana', 'cherry']
print(min(words)) # apple(按字典序)
print(max(words)) # cherry
五、列表元素的增删改查
5.1 修改元素
fruits = ['苹果', '香蕉', '橘子'] # 单个元素修改 fruits[1] = '葡萄' print(fruits) # ['苹果', '葡萄', '橘子'] # 切片赋值——可以修改多个元素 nums = [1, 2, 3, 4, 5] nums[1:4] = [20, 30, 40] print(nums) # [1, 20, 30, 40, 5] # 切片赋值可以改变列表长度! nums[1:4] = [100] # 用1个元素替换3个 print(nums) # [1, 100, 5](列表变短了) nums[1:1] = [200, 300] # 在索引1处插入元素 print(nums) # [1, 200, 300, 100, 5](列表变长了) nums[1:4] = [] # 删除索引1到3的元素 print(nums) # [1, 5] # 清空整个列表 nums[:] = [] print(nums) # []
5.2 添加元素
fruits = ['苹果', '香蕉']
# append():在末尾添加一个元素(最常用)
fruits.append('橘子')
print(fruits) # ['苹果', '香蕉', '橘子']
# insert():在指定位置插入元素
fruits.insert(1, '葡萄')
print(fruits) # ['苹果', '葡萄', '香蕉', '橘子']
fruits.insert(0, '西瓜')
print(fruits) # ['西瓜', '苹果', '葡萄', '香蕉', '橘子']
fruits.insert(len(fruits), '芒果') # 在末尾插入,等价于append
print(fruits)
# extend():追加另一个可迭代对象的所有元素
fruits.extend(['柠檬', '草莓'])
print(fruits) # ['西瓜', '苹果', '葡萄', '香蕉', '橘子', '芒果', '柠檬', '草莓']
# extend和append的区别!
lst = [1, 2, 3]
lst.append([4, 5])
print(lst) # [1, 2, 3, [4, 5]](整个列表作为一个元素添加)
lst2 = [1, 2, 3]
lst2.extend([4, 5])
print(lst2) # [1, 2, 3, 4, 5](列表的元素展开后逐个添加)
# extend可以接受任何可迭代对象
lst3 = [1, 2, 3]
lst3.extend('abc')
print(lst3) # [1, 2, 3, 'a', 'b', 'c']
lst4 = [1, 2, 3]
lst4.extend(range(4, 7))
print(lst4) # [1, 2, 3, 4, 5, 6]
5.3 删除元素
fruits = ['苹果', '香蕉', '橘子', '葡萄', '西瓜', '香蕉']
# pop():弹出并返回指定位置的元素(默认最后一个)
last = fruits.pop()
print(last) # 香蕉
print(fruits) # ['苹果', '香蕉', '橘子', '葡萄', '西瓜']
second = fruits.pop(1)
print(second) # 香蕉
print(fruits) # ['苹果', '橘子', '葡萄', '西瓜']
# 空列表pop会报错
# [].pop() # IndexError
# pop(index)和del的区别:pop有返回值,del没有
fruit = fruits.pop(0) # 拿到被删除的元素
print(fruit) # 苹果
del fruits[0] # 删除但不返回值
print(fruits) # ['葡萄', '西瓜']
# remove():删除第一个匹配的值(按值删除,不是按位置)
nums = [1, 3, 5, 3, 7, 3]
nums.remove(3)
print(nums) # [1, 5, 3, 7, 3](只删除了第一个3)
# 如果值不存在会报错
# nums.remove(100) # ValueError: list.remove(x): x not in list
# 安全删除
def safe_remove(lst, value):
"""安全删除——值不存在时不报错"""
try:
lst.remove(value)
return True
except ValueError:
return False
# clear():清空整个列表
fruits.clear()
print(fruits) # []
# del删除切片
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
del nums[3:7]
print(nums) # [0, 1, 2, 7, 8, 9]
# del删除整个列表
del nums
# print(nums) # NameError: name 'nums' is not defined
5.4 查找和统计
fruits = ['苹果', '香蕉', '橘子', '葡萄', '香蕉', '西瓜']
# index():查找元素第一次出现的位置
print(fruits.index('香蕉')) # 1
print(fruits.index('橘子')) # 2
# 指定查找范围
print(fruits.index('香蕉', 2)) # 4(从索引2开始找)
# print(fruits.index('香蕉', 2, 4)) # ValueError(在[2,4)范围内没找到)
# 元素不存在会报错!需要安全检查
def safe_index(lst, value, default=-1):
"""安全查找——元素不存在时返回默认值"""
try:
return lst.index(value)
except ValueError:
return default
print(safe_index(fruits, '西瓜')) # 5
print(safe_index(fruits, '柠檬')) # -1
# count():统计元素出现的次数
nums = [1, 2, 3, 2, 1, 2, 3, 2, 1]
print(nums.count(1)) # 3
print(nums.count(2)) # 4
print(nums.count(5)) # 0(不存在返回0,不会报错)
# 统计字符串中字符的出现次数
text = list('hello world')
print(text.count('l')) # 3
六、列表的复制——浅拷贝和深拷贝
6.1 赋值不是复制
# 这是大多数初学者都会踩的坑 a = [1, 2, 3] b = a # 这不是复制!这是给同一个列表起了个别名 b[0] = 100 print(a) # [100, 2, 3](a也被改了!) print(b) # [100, 2, 3] # 验证 print(a is b) # True(a和b指向同一个对象) print(id(a) == id(b)) # True
6.2 浅拷贝(创建新列表)
original = [1, 2, 3] # 方式一:切片(最常用) copy1 = original[:] # 方式二:list()构造函数 copy2 = list(original) # 方式三:copy()方法(Python 3.3+) copy3 = original.copy() # 方式四:copy模块的copy函数 import copy copy4 = copy.copy(original) # 验证:四个都是独立的 original[0] = 999 print(original) # [999, 2, 3] print(copy1) # [1, 2, 3] print(copy2) # [1, 2, 3] print(copy3) # [1, 2, 3] print(copy4) # [1, 2, 3]
6.3 浅拷贝的陷阱
# 浅拷贝只复制了第一层,嵌套列表仍然是共享的! original = [[1, 2], [3, 4]] # 浅拷贝 shallow = original.copy() # 修改外层列表——互不影响 original.append([5, 6]) print(original) # [[1, 2], [3, 4], [5, 6]] print(shallow) # [[1, 2], [3, 4]](不受影响) # 修改内层列表——互相影响! original[0][0] = 999 print(original) # [[999, 2], [3, 4], [5, 6]] print(shallow) # [[999, 2], [3, 4]](shallow也被改了!) # 这就是浅拷贝:只复制容器本身,不复制容器内的可变元素
6.4 深拷贝(完全独立)
import copy
original = [[1, 2], [3, 4]]
# 深拷贝——递归复制所有层级的对象
deep = copy.deepcopy(original)
original[0][0] = 999
print(original) # [[999, 2], [3, 4]]
print(deep) # [[1, 2], [3, 4]](完全不受影响!)
# deepcopy可以处理任意深度的嵌套结构
complex_data = [
{'name': '小明', 'scores': [85, 90, 78]},
{'name': '小红', 'scores': [92, 88, 95]},
]
copied = copy.deepcopy(complex_data)
copied[0]['scores'][0] = 0
print(complex_data[0]['scores']) # [85, 90, 78](原数据不变)
print(copied[0]['scores']) # [0, 90, 78]
# 但deepcopy有性能代价,只在需要完全独立复制时使用
# 对于只有一层元素(没有嵌套可变对象)的列表,浅拷贝就够了
记住:如果你的列表只包含不可变元素(数字、字符串、元组等),浅拷贝完全够用。只有嵌套了可变对象(列表、字典等)且你确实需要完全独立时,才需要深拷贝。
七、列表推导式深入
7.1 带条件的推导式
# 过滤:只保留偶数 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] evens = [x for x in numbers if x % 2 == 0] print(evens) # [2, 4, 6, 8, 10] # 过滤+转换:偶数的平方 even_squares = [x ** 2 for x in numbers if x % 2 == 0] print(even_squares) # [4, 16, 36, 64, 100] # if-else在推导式中(注意位置不同!) # if在for后面:过滤条件 # if-else在for前面:转换表达式 labels = ['偶数' if x % 2 == 0 else '奇数' for x in range(10)] print(labels) # ['偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数'] # 多个条件(连续的if) result = [x for x in range(50) if x % 3 == 0 if x % 5 == 0] print(result) # [0, 15, 30, 45](即被15整除的数)
7.2 嵌套推导式
# 二维列表的扁平化
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [item for row in matrix for item in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 等价的双层循环写法
flat2 = []
for row in matrix:
for item in row:
flat2.append(item)
print(flat2) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 转置矩阵
transposed = [[row[i] for row in matrix] for i in range(3)]
print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# 生成乘法表
times_table = [[i * j for j in range(1, 10)] for i in range(1, 10)]
for row in times_table:
print(' '.join(f'{n:2d}' for n in row))
7.3 推导式的性能
import time
# 三种方式对比
n = 1000000
# 方式一:普通for循环
start = time.perf_counter()
result1 = []
for i in range(n):
result1.append(i ** 2)
t1 = time.perf_counter() - start
# 方式二:列表推导式
start = time.perf_counter()
result2 = [i ** 2 for i in range(n)]
t2 = time.perf_counter() - start
# 方式三:map + lambda
start = time.perf_counter()
result3 = list(map(lambda i: i ** 2, range(n)))
t3 = time.perf_counter() - start
print(f'for循环: {t1:.3f}秒')
print(f'推导式: {t2:.3f}秒')
print(f'map+lambda: {t3:.3f}秒')
列表推导式通常比普通for循环快,因为它的循环是在C层面执行的,免去了Python层面的append方法查找和调用开销。
八、实战:列表的常见应用模式
8.1 去重
# 保持顺序的去重(3.7+版本用dict保持顺序)
def unique_ordered(items):
"""去重且保持原始顺序"""
seen = set()
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
lst = [1, 3, 2, 1, 5, 3, 2, 4, 1]
print(unique_ordered(lst)) # [1, 3, 2, 5, 4]
# Python 3.7+ 也可以用dict
print(list(dict.fromkeys(lst))) # [1, 3, 2, 5, 4]
# 不关心顺序的去重
print(list(set(lst))) # [1, 2, 3, 4, 5](顺序不保证)
8.2 分组
# 将列表按条件分组
def partition(lst, predicate):
"""根据条件将列表分为两组"""
true_list = []
false_list = []
for item in lst:
if predicate(item):
true_list.append(item)
else:
false_list.append(item)
return true_list, false_list
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens, odds = partition(numbers, lambda x: x % 2 == 0)
print(f'偶数: {evens}') # [2, 4, 6, 8, 10]
print(f'奇数: {odds}') # [1, 3, 5, 7, 9]
# 更细致的分组——使用字典
def group_by(items, key_func):
"""按key_func的返回值将元素分组"""
groups = {}
for item in items:
key = key_func(item)
if key not in groups:
groups[key] = []
groups[key].append(item)
return groups
words = ['apple', 'banana', 'apricot', 'cherry', 'blueberry', 'coconut']
by_first_letter = group_by(words, lambda w: w[0])
for letter, group in sorted(by_first_letter.items()):
print(f'{letter}: {group}')
8.3 分块处理
def chunked(lst, chunk_size):
"""将列表分割为指定大小的块"""
return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
large_list = list(range(1, 101))
chunks = chunked(large_list, 10)
for i, chunk in enumerate(chunks):
print(f'块{i + 1}: {chunk[0]}...{chunk[-1]}(共{len(chunk)}个)')
# 实际应用:分批处理数据
def process_in_batches(items, batch_size=50):
"""分批处理大量数据"""
results = []
for i in range(0, len(items), batch_size):
batch = items[i:i + batch_size]
# 模拟批量处理
batch_result = [item * 2 for item in batch]
results.extend(batch_result)
return results
8.4 列表的链式操作
# 数据管道:过滤→转换→排序→取前N个
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]
# 步骤:去重 → 只保留偶数 → 平方 → 排序 → 取前3个
result = sorted(
[x ** 2 for x in set(data) if x % 2 == 0],
reverse=True
)[:3]
print(result) # [64, 36, 16]
# 更易读的分步写法(推荐用于复杂逻辑)
unique = set(data)
evens = [x for x in unique if x % 2 == 0]
squared = [x ** 2 for x in evens]
top3 = sorted(squared, reverse=True)[:3]
print(top3) # [64, 36, 16]
九、性能优化与列表的底层原理
9.1 列表的扩容机制
# Python列表使用动态数组实现
# 内部有一个预留的容量,当元素填满时会自动扩容
import sys
# 观察列表的内存增长
lst = []
prev_size = sys.getsizeof(lst)
print(f'空列表大小: {prev_size} 字节')
for i in range(20):
lst.append(i)
new_size = sys.getsizeof(lst)
if new_size != prev_size:
print(f'元素数 {len(lst):2d}: {prev_size} → {new_size} 字节(扩容了)')
prev_size = new_size
# 可以看到列表在特定时刻扩容(通常是指数增长策略)
列表内部使用了一种"过度分配"策略——当需要扩容时,不是只增加1个位置,而是分配更多空间。这样可以减少频繁的内存分配操作,提高append的性能。这就是为什么 lst.append() 的平均时间复杂度是 O(1)。
9.2 预分配 vs 逐步append
import time
n = 1000000
# 方式一:逐步append(自动扩容)
start = time.perf_counter()
lst1 = []
for i in range(n):
lst1.append(i)
t1 = time.perf_counter() - start
# 方式二:预分配(用乘法创建初始大小)
start = time.perf_counter()
lst2 = [0] * n # 一次性分配
for i in range(n):
lst2[i] = i
t2 = time.perf_counter() - start
# 方式三:列表推导式(最快,内部有优化)
start = time.perf_counter()
lst3 = [i for i in range(n)]
t3 = time.perf_counter() - start
print(f'逐步append: {t1:.3f}秒')
print(f'预分配: {t2:.3f}秒')
print(f'推导式: {t3:.3f}秒')
9.3 避免不必要的列表复制
# 很多操作返回迭代器而不是列表,可以节省内存
# 不必要地创建中间列表(浪费内存)
nums = range(1000000)
# result = [x ** 2 for x in nums if x % 2 == 0] # 内存中创建整个列表
# total = sum(result)
# 更优:使用生成器表达式(惰性求值)
total = sum(x ** 2 for x in nums if x % 2 == 0)
# 方括号变圆括号,不创建中间列表
# 需要索引时用enumerate而不是range(len())
items = ['a', 'b', 'c', 'd', 'e']
# 不推荐
for i in range(len(items)):
print(i, items[i])
# 推荐
for i, item in enumerate(items):
print(i, item)
十、本篇小结
列表是Python中最灵活、最常用的容器类型:
- 四个核心特征:有序、可变、可重复、可包含任意类型
- 七种创建方式:字面量
[]、list()、列表推导式、乘法、split()、range()、从其他数据源 - 增删改查:
append()/insert()/extend()增,pop()/remove()/del/clear()删,索引赋值改,index()/count()查 - 浅拷贝 vs 深拷贝:
[:]或.copy()是浅拷贝(内层对象共享),copy.deepcopy()是完全独立复制 - 列表推导式:Pythonic的列表创建方式,简洁且性能更优
- 存储引用:列表存储的是对象的引用,不是对象本身——这是理解列表行为的关键
列表是Python中最重要的数据结构,没有之一。本文涵盖了列表的创建和基本操作,下一篇我们将深入索引取值和切片操作——这是列表最强大的特性之一,也是区分Python新手和老手的重要分水岭。
到此这篇关于Python基础指南之列表list的创建与基本操作详解的文章就介绍到这了,更多相关Python列表list创建与操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Python如何保护代码和数据,常见的安全漏洞及应对措施有哪些?
本文介绍了Python安全编程的重要性,并分享了常见的安全漏洞及应对措施、安全编程最佳实践、安全库的使用、安全配置等内容,同时,还对比了Python和Rust的安全特性,并推荐了一些实践项目,最后提出了学习方法和技巧,鼓励大家不断提高安全意识2026-05-05
Python使用execute_script模拟鼠标滚动、鼠标点击等示例
文章介绍了Python使用Selenium执行JavaScript来绕过网站对爬虫的限制,包括模拟点击、拦截弹出窗口、创建并派发点击事件、模拟鼠标悬停后点击和滚动到元素并点击等方法2025-02-02
python生成可执行exe控制Microsip自动填写号码并拨打功能
这篇文章主要介绍了python生成可执行exe控制Microsip自动填写号码并拨打,在这需要注意一个问题,必须是已经运行Microsip.exe文件,具体实现代码跟随小编一起看看吧2021-06-06


最新评论