news 2026/8/27 2:15:40

Python列表从入门到精通:创建、切片、增删改查与性能优化全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python列表从入门到精通:创建、切片、增删改查与性能优化全解析

1. 项目概述:为什么列表是Python入门的第一个“坎”?

如果你刚开始学Python,学完变量、数据类型和基础语法,感觉一切都很顺畅,那么恭喜你,马上要遇到第一个真正能让你感受到编程威力的东西了——列表。很多人把列表当作一个简单的“数据容器”来学,这其实大大低估了它的价值。在我带过的很多新手项目中,列表是第一个分水岭:会用列表和真正理解列表的人,写出的代码效率和可读性天差地别。

简单说,列表就是一个可以装下任何东西的“魔法口袋”。你可以把数字、字符串、甚至其他列表都塞进去,并且能随时取出、替换、增加或删除。这节课,我们不搞那些枯燥的教科书定义,就从一个实际场景切入:假设你要管理一个线上读书会成员的信息,包括名字、加入月份和本月阅读时长(小时)。用单个变量存?你得声明几十个变量,管理起来是场灾难。用列表,一行代码就能轻松搞定。这就是列表要解决的第一个核心问题:如何高效地组织和管理一组有序的、可能随时变化的数据。

这节课是“常用数据结构之列表”的第一部分,我们会聚焦在最核心、最常用的操作上。目标是让你学完就能立刻用起来,处理你手头的数据。我们会从创建和访问这个“口袋”开始,到如何往里面“放东西”、“拿东西”、“换东西”,最后深入到“切片”这个列表的灵魂操作。别被“数据结构”这个词吓到,你就把它理解为“整理数据的工具箱”,而列表是你打开工具箱后,最顺手、最常用的那把螺丝刀。

2. 列表的核心操作全解析:从创建到访问

2.1 创建列表的四种姿势与选择逻辑

创建列表,Python给了你极大的灵活性,但不同的方式适用于不同的场景,选对了能让代码意图更清晰。

第一种,也是最直接的方式:使用方括号[]

# 创建一个空列表,像一个准备装东西的空盒子 members = [] # 创建一个包含初始元素的列表 book_club_members = [‘Alice‘, ‘Bob‘, ‘Charlie‘] reading_hours = [12, 8, 15]

这是你未来90%的情况下会使用的方式。它直观、简洁,一眼就能看出你在定义一个列表。空列表常用于初始化一个后续需要动态填充的数据容器,比如在循环中收集结果。

第二种:使用list()构造函数。

# 将其他可迭代对象转换为列表 name_tuple = (‘Alice‘, ‘Bob‘) # 这是一个元组 member_list_from_tuple = list(name_tuple) # 转换成列表:[‘Alice‘, ‘Bob‘] # 将字符串的每个字符拆成列表 letters = list(‘Python‘) # 结果:[‘P‘, ‘y‘, ‘t‘, ‘h‘, ‘o‘, ‘n‘] # 创建空列表 empty_list = list() # 等价于 []

list()的强大之处在于“转换”。当你从函数得到的是一个元组(tuple)、集合(set),或者需要把字符串拆成单个字符时,list()是你的首选。但请注意,如果你只是想要一个包含已知元素的列表,直接使用[]在性能和可读性上都更优。

第三种:列表推导式(List Comprehension)。

# 生成一个1到10的平方数列表 squares = [x**2 for x in range(1, 11)] # 结果:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] # 生成一个读书会成员阅读时长超过10小时的名单 members = [‘Alice‘, ‘Bob‘, ‘Charlie‘, ‘Diana‘] hours = [12, 8, 15, 9] active_members = [member for member, hour in zip(members, hours) if hour > 10] # 结果:[‘Alice‘, ‘Charlie‘]

列表推导式是Python的语法糖,也是体现其优雅之处的特性之一。它用一行代码完成了一个循环创建和条件筛选的过程。虽然这部分我们后续课程会深入讲,但你现在需要知道它的存在。它特别适合从一个现有序列中,通过某种规则生成一个新列表的场景,代码紧凑且执行效率通常比普通的for循环稍高。

第四种:使用乘法*操作符进行重复。

# 创建一个包含5个0的列表,常用于初始化固定长度的计数列表 zero_list = [0] * 5 # 结果:[0, 0, 0, 0, 0] # 创建一个嵌套列表的“坑” nested = [[]] * 3 # 结果:[[], [], []]

这种方式非常方便,但有一个天坑需要特别注意:当列表的元素是可变对象(如另一个列表、字典)时,使用*复制的是这个对象的引用,而不是创建独立的对象。这意味着nested中的三个子列表,实际上是同一个列表对象!修改其中任何一个,其他两个都会跟着变。这常常是初学者Bug的来源。对于可变对象,安全的初始化应该使用列表推导式:nested = [[] for _ in range(3)]

注意:在项目初期,如果你不确定,优先使用方括号[]创建列表。list()用于转换,列表推导式用于复杂生成,乘法初始化要警惕可变对象陷阱。

2.2 访问元素:索引与越界陷阱

创建了列表,接下来就要从中取数据。访问依赖的是“索引”,即元素在列表中的位置编号。

正索引与负索引Python的列表索引从0开始,这是编程界的通用约定。第一个元素的索引是0,第二个是1,以此类推。

members = [‘Alice‘, ‘Bob‘, ‘Charlie‘, ‘Diana‘] print(members[0]) # 输出:Alice print(members[2]) # 输出:Charlie

更妙的是,Python支持负索引。-1表示最后一个元素,-2表示倒数第二个,这在你想获取列表末尾元素时极其方便,无需先计算列表长度。

print(members[-1]) # 输出:Diana print(members[-2]) # 输出:Charlie

索引越界:最常见的错误之一如果你尝试访问一个不存在的索引,Python会抛出IndexError

print(members[4]) # IndexError: list index out of range print(members[-5]) # 同样会越界

如何避免?在访问前,尤其是在索引是变量时,先判断其是否在有效范围内。可以使用len()函数获取列表长度。

index = 4 if 0 <= index < len(members): print(members[index]) else: print(f“索引 {index} 超出范围,列表长度为 {len(members)}“)

在实际脚本编写中,更Pythonic的做法是使用异常处理(try...except),但对于初学者,先养成检查的习惯很重要。

2.3 修改元素:列表的“可变性”体现

字符串是不可变的,你无法修改字符串中的某个字符。但列表是“可变”数据结构,这是它最核心的特性之一。你可以直接通过索引来赋值,改变列表中特定位置的元素。

members = [‘Alice‘, ‘Bob‘, ‘Charlie‘] print(members) # 输出:[‘Alice‘, ‘Bob‘, ‘Charlie‘] members[1] = ‘Benjamin‘ # 将索引1(第二个元素)从‘Bob‘改为‘Benjamin‘ print(members) # 输出:[‘Alice‘, ‘Benjamin‘, ‘Charlie‘]

这个操作是“原地修改”,列表对象本身的内存地址没有改变,只是其内部的内容发生了变化。理解“可变性”是理解后续所有列表方法(如append,insert,remove)的基础,因为它们大多都是在原列表上直接操作。

3. 列表的“灵魂”操作:切片

如果说索引是“点”,那么切片就是“线”和“面”。切片允许你一次性获取列表的一个子序列,它是Python序列类型中最强大、最优雅的特性之一。

3.1 切片基础语法与三个参数

切片的基本语法是list[start:stop:step]

  • start:起始索引(包含)。默认为0。
  • stop:结束索引(不包含)。默认为列表长度。
  • step:步长,即每隔几个元素取一个。默认为1。
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 获取第2到第5个元素(索引1到4,不包含索引5) sub1 = numbers[1:5] # 结果:[1, 2, 3, 4] # 获取前三个元素 sub2 = numbers[:3] # 结果:[0, 1, 2] # 获取从索引3到末尾的所有元素 sub3 = numbers[3:] # 结果:[3, 4, 5, 6, 7, 8, 9] # 获取整个列表的副本(浅拷贝) sub4 = numbers[:] # 结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 每隔一个元素取一个 sub5 = numbers[::2] # 结果:[0, 2, 4, 6, 8] # 从后往前取,步长为-1,即列表反转 reverse_numbers = numbers[::-1] # 结果:[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] # 从索引8开始,往前取到索引2(不包含2),步长为-2 sub6 = numbers[8:2:-2] # 结果:[8, 6, 4]

关键理解stop索引指向的元素是取不到的。记住一个口诀:“顾头不顾尾”。numbers[1:5]获取的是索引为1, 2, 3, 4的元素。这种设计避免了在计算范围时出现“差一错误”。

3.2 切片的高级应用与内存视图

切片操作返回的是原列表的一个新列表,但这里有一个非常重要的细节:对于列表中的不可变元素(如整数、字符串),切片是创建了一份独立的拷贝;然而,对于嵌套的可变对象,情况会复杂一些(这涉及到“浅拷贝”概念,后续课程会深入)。

切片的一个强大应用是原地修改列表的某个区间

data = [‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘] data[1:4] = [‘x‘, ‘y‘, ‘z‘] # 将索引1到3的元素替换为新列表 print(data) # 输出:[‘a‘, ‘x‘, ‘y‘, ‘z‘, ‘e‘, ‘f‘] # 甚至可以替换为长度不同的列表 data[1:4] = [‘only_one‘] # 用单个元素替换一个区间 print(data) # 输出:[‘a‘, ‘only_one‘, ‘e‘, ‘f‘]

这个特性让你可以非常灵活地批量更新列表内容,而无需编写复杂的循环。

3.3 切片与循环的搭配:高效数据处理

在处理数据时,我们经常需要按块处理。例如,有一个包含100个用户ID的列表,你想每次处理10个。

all_user_ids = list(range(100)) # 假设是0到99的ID batch_size = 10 for i in range(0, len(all_user_ids), batch_size): batch = all_user_ids[i:i + batch_size] # 关键切片操作 print(f“正在处理批次,ID范围:{batch}“) # 在这里执行你的处理逻辑,比如调用API

这段代码中,range(0, len(all_user_ids), batch_size)生成了起始索引:0, 10, 20, ...。切片all_user_ids[i:i + batch_size]则依次取出 [0:10], [10:20], [20:30]... 的子列表。这种模式在数据分批、分页查询等场景中极为常见。

4. 列表元素的增删改查实战

掌握了创建、访问和切片,列表的基本骨架就有了。接下来是让它“动”起来,即动态地增加、删除和查找元素。这是列表作为动态数组的核心能力。

4.1 增加元素:尾部追加与任意位置插入

向列表添加元素,最常用的两个方法是append()insert()

append(item):在列表末尾添加一个元素。这是效率最高的添加方式,时间复杂度为O(1)。因为它只需要在数组末尾预留的空间里放上新元素。

todo_list = [‘写博客‘, ‘读文档‘] todo_list.append(‘调试代码‘) print(todo_list) # 输出:[‘写博客‘, ‘读文档‘, ‘调试代码‘]

append()是“就地修改”,直接改变原列表,没有返回值(返回None)。一个常见错误是误以为它有返回值并赋值:

new_list = todo_list.append(‘新任务‘) # 错误!append()返回None print(new_list) # 输出:None print(todo_list) # 输出:[..., ‘新任务‘], 原列表已修改

insert(index, item):在指定索引位置插入一个元素。这会将原索引位置及之后的元素都向后移动一位,因此时间复杂度是O(n),在列表很长且在前部插入时效率较低。

todo_list = [‘写博客‘, ‘读文档‘, ‘调试代码‘] todo_list.insert(1, ‘开会‘) # 在索引1(第二个位置)插入 print(todo_list) # 输出:[‘写博客‘, ‘开会‘, ‘读文档‘, ‘调试代码‘]

当你需要在列表开头插入时,insert(0, item)很方便,但性能不如append()。如果频繁在开头插入,可能需要考虑使用collections.deque(双端队列)。

extend(iterable):批量追加。append()一次加一个,extend()则可以将另一个可迭代对象(如列表、元组、字符串)中的所有元素,逐个添加到列表末尾。

list_a = [1, 2, 3] list_b = [4, 5, 6] list_a.extend(list_b) print(list_a) # 输出:[1, 2, 3, 4, 5, 6] # 与 += 运算符效果相同 list_a += [7, 8] print(list_a) # 输出:[1, 2, 3, 4, 5, 6, 7, 8] # 注意与append的区别 list_c = [1, 2] list_c.append([3, 4]) print(list_c) # 输出:[1, 2, [3, 4]], 整个列表被当作一个元素添加

extend()比用循环逐个append()更简洁,效率也通常更高。

4.2 删除元素:按值、按索引与清空

删除同样有多种方式,需要根据场景选择。

remove(value):删除第一个匹配到的指定值。

fruits = [‘apple‘, ‘banana‘, ‘orange‘, ‘banana‘] fruits.remove(‘banana‘) print(fruits) # 输出:[‘apple‘, ‘orange‘, ‘banana‘]

注意,它只删除第一个出现的‘banana‘。如果值不存在,会引发ValueError。因此,安全的做法是先判断:

if ‘grape‘ in fruits: fruits.remove(‘grape‘)

pop([index]):删除并返回指定索引的元素。如果不提供索引,默认删除并返回最后一个元素(栈的“弹出”操作)。

stack = [1, 2, 3, 4, 5] last_item = stack.pop() print(last_item) # 输出:5 print(stack) # 输出:[1, 2, 3, 4] second_item = stack.pop(1) # 删除索引1的元素 print(second_item) # 输出:2 print(stack) # 输出:[1, 3, 4]

pop()在你需要同时使用被删除元素的值时非常有用。删除中间元素同样会导致后续元素前移,时间复杂度为O(n)。

del语句:按索引或切片删除。del是Python语句,不是列表方法。它可以删除整个列表、列表中的某个元素或一个切片。

data = [‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘] del data[2] # 删除索引2的元素‘c‘ print(data) # 输出:[‘a‘, ‘b‘, ‘d‘, ‘e‘] del data[1:3] # 删除切片[1:3]即索引1和2的元素(‘b‘, ‘d‘) print(data) # 输出:[‘a‘, ‘e‘] # del data # 这会删除整个变量data,后续再使用data会报错

del非常直接,但它不返回被删除的值。当你只是想丢弃某些元素而不关心其值时,用del很合适。

clear():清空列表所有元素。这会将列表重置为空列表[],但列表对象本身仍然存在。

temp_data = [1, 2, 3, 4, 5] temp_data.clear() print(temp_data) # 输出:[]

4.3 查找与统计:判断存在与计数

index(value, [start, [stop]]):返回第一个匹配值的索引。

colors = [‘red‘, ‘green‘, ‘blue‘, ‘green‘, ‘yellow‘] idx = colors.index(‘green‘) print(idx) # 输出:1 # 可以指定搜索范围 idx2 = colors.index(‘green‘, 2) # 从索引2开始找 print(idx2) # 输出:3 # 如果找不到,会引发ValueError # idx3 = colors.index(‘purple‘) # ValueError

同样,在使用前用in运算符判断是否存在是更稳妥的做法。

count(value):统计某个值在列表中出现的次数。

scores = [85, 90, 85, 78, 90, 85] count_85 = scores.count(85) print(count_85) # 输出:3

in/not in运算符:成员关系测试。这是最常用、最高效的查找方式之一,用于判断一个元素是否存在于列表中。

shopping_list = [‘milk‘, ‘eggs‘, ‘bread‘] if ‘eggs‘ in shopping_list: print(“鸡蛋已经在购物清单里了。“) if ‘apple‘ not in shopping_list: print(“还没买苹果。“)

in运算符会遍历列表(时间复杂度O(n))直到找到目标或遍历完。对于非常大的列表,频繁查找效率可能成为瓶颈,这时可以考虑使用集合(set)或字典(dict),它们基于哈希表,查找效率接近O(1)。

5. 列表排序、反转与复制:让数据井然有序

5.1 排序:sort()sorted()的抉择

排序是数据处理中的高频操作。Python提供了两种方式,它们有本质区别。

list.sort(key=None, reverse=False):原地排序。这个方法直接修改原列表,使其按升序排列。它没有返回值(或者说返回None)。

numbers = [3, 1, 4, 1, 5, 9, 2] numbers.sort() print(numbers) # 输出:[1, 1, 2, 3, 4, 5, 9] # 降序排序 numbers.sort(reverse=True) print(numbers) # 输出:[9, 5, 4, 3, 2, 1, 1] # 按字符串长度排序 words = [‘apple‘, ‘fig‘, ‘banana‘, ‘date‘] words.sort(key=len) # key参数指定一个函数,用于提取比较键 print(words) # 输出:[‘fig‘, ‘date‘, ‘apple‘, ‘banana‘]

key参数非常强大。例如,对一个包含元组的列表,按元组的第二个元素排序:

students = [(‘Alice‘, 88), (‘Bob‘, 95), (‘Charlie‘, 78)] students.sort(key=lambda x: x[1], reverse=True) # 按分数降序 print(students) # 输出:[(‘Bob‘, 95), (‘Alice‘, 88), (‘Charlie‘, 78)]

sorted(iterable, key=None, reverse=False):返回新列表。这个内置函数接受任何可迭代对象,返回一个新的、排序后的列表,不改变原对象。

original = [3, 1, 4, 1, 5] new_sorted_list = sorted(original) print(original) # 输出:[3, 1, 4, 1, 5] (未改变) print(new_sorted_list) # 输出:[1, 1, 3, 4, 5] # 同样支持key和reverse参数 sorted_by_len = sorted(words, key=len)

如何选择?

  • 如果你想修改原列表,并且不再需要原始顺序,用list.sort(),它更省内存。
  • 如果你想保留原列表,或者排序的对象不是列表(如元组、字符串),用sorted()
  • 一个简单的记忆法:sort()是列表的“动作”(改变自己),sorted()是Python的“函数”(给你一个新结果)。

5.2 反转:reverse()与切片[::-1]

list.reverse():原地反转列表顺序。

nums = [1, 2, 3, 4, 5] nums.reverse() print(nums) # 输出:[5, 4, 3, 2, 1]

使用切片[::-1]:创建反转后的新列表。

nums = [1, 2, 3, 4, 5] reversed_nums = nums[::-1] print(nums) # 输出:[1, 2, 3, 4, 5] (未变) print(reversed_nums) # 输出:[5, 4, 3, 2, 1]

选择原则同上:想改变原列表用reverse(),想得到新列表用切片。

5.3 复制:浅拷贝与深拷贝的陷阱

这是列表操作中最容易出错的地方之一。简单的赋值=不会创建列表的副本,它只是创建了一个指向同一内存地址的新标签(别名)。

original = [[1, 2], [3, 4]] alias = original # 这只是起别名 alias[0][0] = ‘changed‘ print(original) # 输出:[[‘changed‘, 2], [3, 4]]!原列表也被改了

这显然不是我们想要的。我们需要“拷贝”。

浅拷贝 (Shallow Copy):只拷贝第一层。创建浅拷贝有几种方式:

  1. 使用切片[:]
  2. 使用list()构造函数。
  3. 使用copy()方法(Python 3.3+)。
import copy original = [[1, 2], [3, 4]] shallow_copy = original[:] # 或 list(original) 或 original.copy() # 修改第一层,原列表不受影响 shallow_copy.append([5, 6]) print(original) # 输出:[[1, 2], [3, 4]] print(shallow_copy) # 输出:[[1, 2], [3, 4], [5, 6]] # 但是!修改第二层(嵌套的可变对象),原列表依然受影响! shallow_copy[0][0] = ‘changed‘ print(original) # 输出:[[‘changed‘, 2], [3, 4]]!问题出现了 print(shallow_copy) # 输出:[[‘changed‘, 2], [3, 4], [5, 6]]

浅拷贝创建了一个新列表,但新列表中的元素(例如[1, 2]这个子列表)仍然是原列表中元素的引用。所以修改嵌套对象,两边会同步变化。

深拷贝 (Deep Copy):递归拷贝所有层级。使用copy模块的deepcopy()函数。

import copy original = [[1, 2], [3, 4]] deep_copy = copy.deepcopy(original) deep_copy[0][0] = ‘changed‘ print(original) # 输出:[[1, 2], [3, 4]] (完全不受影响) print(deep_copy) # 输出:[[‘changed‘, 2], [3, 4]]

深拷贝会递归地复制所有嵌套的可变对象,创建一个完全独立的副本。代价是如果数据结构非常复杂(嵌套很深或很大),深拷贝可能比较耗时和耗内存。

选择建议

  • 如果列表只包含不可变对象(数字、字符串、元组),浅拷贝就足够了,效果和深拷贝一样。
  • 如果列表包含其他可变对象(列表、字典),并且你希望副本完全独立,必须使用深拷贝。
  • 在不确定的情况下,或者数据结构不复杂时,使用深拷贝更安全。

6. 列表的遍历与性能考量

遍历列表是所有操作的基础。最直接的是for循环。

6.1 基本遍历:for循环

fruits = [‘apple‘, ‘banana‘, ‘cherry‘] for fruit in fruits: # 直接遍历元素 print(fruit) # 如果需要索引,使用 enumerate() for index, fruit in enumerate(fruits): print(f“索引 {index} 的水果是 {fruit}“)

enumerate()函数返回一个迭代器,每次产生一个(索引, 元素)的元组,非常方便。

6.2 遍历中的“坑”:不要在遍历时修改列表长度

这是一个经典错误。如果你在遍历列表的同时,又添加或删除了元素,可能会导致意想不到的结果,甚至程序崩溃。

# 错误示例:想删除所有偶数 numbers = [1, 2, 3, 4, 5, 6] for num in numbers: if num % 2 == 0: numbers.remove(num) # 在遍历中删除元素 print(numbers) # 输出可能是:[1, 3, 5, 6]? 为什么6还在?

因为删除元素后,列表长度和索引关系发生了变化,迭代器会错乱。正确的做法是:

  1. 创建新列表(列表推导式):
    numbers = [1, 2, 3, 4, 5, 6] numbers = [num for num in numbers if num % 2 != 0] print(numbers) # 输出:[1, 3, 5]
  2. 遍历副本
    numbers = [1, 2, 3, 4, 5, 6] for num in numbers[:]: # 遍历原列表的切片副本 if num % 2 == 0: numbers.remove(num) # 修改原列表 print(numbers) # 输出:[1, 3, 5]
  3. 反向遍历(适用于删除):
    numbers = [1, 2, 3, 4, 5, 6] for i in range(len(numbers)-1, -1, -1): # 从后往前遍历索引 if numbers[i] % 2 == 0: del numbers[i] print(numbers) # 输出:[1, 3, 5]

推荐使用第一种(创建新列表)或第二种(遍历副本)方法,它们更清晰、更安全。

6.3 列表与循环的性能

列表的查找(in)、按索引访问(list[i])是O(1)操作,非常快。但在列表开头或中间插入/删除元素(insert,pop(i),remove)是O(n)操作,因为需要移动后续所有元素。当列表很大(比如数十万、百万级元素)且需要频繁在非尾部位置增删时,列表的性能会成为瓶颈。

性能优化小技巧

  • 预分配空间:如果你事先知道列表的大致长度,可以用[None] * size初始化,然后通过索引赋值,这比反复append()在极大量数据时可能稍快(因为避免了多次动态扩容)。
  • 考虑使用collections.deque:如果你需要频繁在列表两端(头部和尾部)进行添加或删除操作,双端队列dequeappendleft()popleft()操作是O(1),比列表的insert(0, item)pop(0)(O(n))高效得多。
  • 成员检查的替代:如果需要非常频繁地判断一个元素是否存在于一个集合中,且不关心顺序和重复,使用set(集合)的查找效率是O(1),远高于列表的O(n)。

7. 列表推导式:优雅与效率的典范

虽然列表推导式通常被放在更进阶的课程,但它的实用性太强,值得在这里提前了解其基础。它提供了一种简洁、高效创建列表的方法。

7.1 基础语法与转换

基本形式:[expression for item in iterable]

# 将0-9的数字转换为字符串 str_numbers = [str(i) for i in range(10)] # 结果:[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘] # 计算0-9的平方 squares = [x*x for x in range(10)] # 结果:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

它等价于一个for循环:

squares = [] for x in range(10): squares.append(x*x)

但列表推导式更简洁,并且在CPython解释器中,由于其实现方式,通常比等效的for循环稍快一些。

7.2 带条件的过滤

形式:[expression for item in iterable if condition]

# 获取0-19中所有的偶数 evens = [x for x in range(20) if x % 2 == 0] # 结果:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # 处理读书会数据:筛选阅读时长大于10小时的成员 members = [‘Alice‘, ‘Bob‘, ‘Charlie‘, ‘Diana‘] hours = [12, 8, 15, 9] active_members = [members[i] for i in range(len(members)) if hours[i] > 10] # 结果:[‘Alice‘, ‘Charlie‘]

这里的if是过滤条件,只有满足条件的item才会进入表达式计算并加入新列表。

7.3 嵌套循环与多重条件

列表推导式可以嵌套,用于处理更复杂的数据平铺或组合。

# 生成一个二维坐标列表 (x, y),其中x和y都在0-2范围内 coords = [(x, y) for x in range(3) for y in range(3)] # 结果:[(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)] # 等价于嵌套for循环 coords = [] for x in range(3): for y in range(3): coords.append((x, y))

也可以组合多个if条件。

# 生成一个列表,包含0-9中能被2或3整除的数 numbers = [x for x in range(10) if x % 2 == 0 or x % 3 == 0] # 结果:[0, 2, 3, 4, 6, 8, 9]

使用建议:列表推导式让代码更紧凑、更具可读性(一旦你熟悉了这种语法)。但也要避免过度使用,特别是嵌套层数过多或逻辑非常复杂时,可能会降低代码的可读性。一个经验法则是:如果推导式超过了两行,或者包含了复杂的if-else逻辑,考虑拆分成普通的for循环可能更清晰。

列表是Python编程的基石,几乎无处不在。从简单的数据存储到复杂的数据处理流水线,列表都扮演着核心角色。理解并熟练运用列表的创建、访问、切片、增删改查、排序遍历以及推导式,你就掌握了用Python处理有序数据集合的最重要工具。在后续的课程中,我们会将列表与循环、函数、其他数据结构(元组、字典、集合)结合,解决更实际的问题。现在,最好的学习方式就是打开你的编辑器,把上面的例子都敲一遍,然后尝试用列表去整理你手头的一些数据,比如管理你的待办事项、记录一周的开销、或者分析一段文本中的单词。实践出真知,动手写代码是理解这一切的唯一捷径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 2:15:40

用概念激活向量(CAV)分析L2口语评分模型中的偏见

1. 这篇文章真正要解决的问题 如果你做过自动口语评分系统&#xff0c;或者接触过语音评测产品&#xff0c;大概率会遇到一个让人头疼的现象&#xff1a;模型在公开测试集上准确率不错&#xff0c;但放到真实口语考试场景里&#xff0c;某些考生群体的分数系统性地偏低或偏高。…

作者头像 李华
网站建设 2026/8/27 2:15:11

向量缓存链路的拆解顺序

向量缓存链路的拆解顺序 把日志字段留在记录里 向量缓存链路的拆解顺序这件事最怕只留下结论&#xff0c;没有留下判断过程。实际处理时&#xff0c;先选一条具体路径&#xff0c;把进入条件、经过的组件和结束状态写下来。正常场景当然要测&#xff0c;但更该看参数缺失、依赖…

作者头像 李华
网站建设 2026/8/27 2:14:54

AI手机二次付费背后:端云模型与Token成本真相

最近很多人在讨论一个现象&#xff1a;花大几千买了 AI 手机&#xff0c;结果发现最亮眼的那几个功能都要额外开通会员。“AI 消除”用几次就提示额度不足&#xff0c;“智能助手”想让它自动订餐厅&#xff0c;弹出的却是订阅付费页。于是网上出现一种说法&#xff1a;买 AI 手…

作者头像 李华
网站建设 2026/8/27 2:13:59

计算机毕业设计之基于Android的考研管理系统的设计与实现

本文介绍了一款使用SpringBoot和 uni-app开发的Android的考研管理系统&#xff0c;及其设计与实现过程。根据软件工程对软件系统开发定制的规则和标准&#xff0c;详细的介绍了系统的分析与设计过程&#xff0c;并且详细的概括了系统的开发与测试过程。本文的管理系统使用了jav…

作者头像 李华
网站建设 2026/8/27 2:13:35

C# WinForm商品进销存系统源码解析:从架构到答辩全攻略

简介&#xff1a;进销存系统是企业信息化中的核心业务应用&#xff0c;覆盖采购、销售与库存三大环节。在.NET技术体系中&#xff0c;C#与WinForm是构建桌面端管理系统的经典组合&#xff0c;配合SQL Server数据库&#xff0c;能够快速实现数据驱动的业务闭环。WinForm控件拖拽…

作者头像 李华
网站建设 2026/8/27 2:13:04

自制低成本PCR仪:用Arduino和半导体制冷片实现精确温控

说实话&#xff0c;我第一次把半导体制冷片、一块铝板和Arduino拼在一起的时候&#xff0c;也没想到它真能跑出PCR产物。这台自制PCR循环仪全部零件成本大概810元&#xff0c;而实验室里那台入门级商用机&#xff0c;报价两万八。更让我意外的是&#xff0c;用它跑出来的目标条…

作者头像 李华