尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python列表完全指南:从创建、增删改查到实战应用

Python列表完全指南:从创建、增删改查到实战应用 1. 从“购物清单”到“数据容器”为什么列表是Python的基石如果你刚开始学Python可能会觉得“数据结构”这个词有点唬人听起来像是计算机科学里高深莫测的东西。别被它吓到你可以把它想象成你日常生活中整理物品的容器。比如你有一个书架一种数据结构来整理书一个衣柜另一种数据结构来整理衣服。在Python里列表List就是你最常用、最顺手的一个“万能收纳盒”。今天这堂课我们就来彻底搞懂这个盒子从怎么造一个空盒子开始到怎么往里面放东西、取东西、整理东西甚至把盒子拆开重组。为什么列表如此重要几乎你写的每一个有点用处的Python程序都离不开它。你想处理一批用户的名字用列表。你想记录一系列传感器的读数用列表。你想保存从网页上爬下来的一堆链接还是用列表。它是有序的、可变的这意味着你可以随时往里面加东西、减东西或者改变里面东西的顺序就像你整理一个真正的列表一样方便。网络上那些热门的搜索词比如“python 列表 自动化 example”、“列表切片”、“for if列表表达式”都指向了大家在实际使用列表时最关心、也最容易遇到问题的操作。我们这节课的目标就是让你不仅能看懂这些代码更能自己熟练地写出来。2. 列表的诞生四种创建方式与内部探秘在你能对列表做任何酷炫操作之前你得先有一个列表。创建列表的方法不止一种每种方法都有其适用的场景。理解这些创建方式是理解列表行为的第一步。2.1 最直观的方式使用方括号[]这是最常用、最直接的方法。你可以创建一个空列表也可以直接初始化一个包含元素的列表。# 创建一个空列表就像一个还没写字的便签本 shopping_list [] todo_list list() # 使用list()函数创建空列表效果相同 # 创建一个包含初始元素的列表 fruits [apple, banana, orange, grape] numbers [1, 2, 3, 4, 5] mixed_bag [42, hello, 3.14, True] # 列表可以包含不同类型的元素这里有一个非常重要的特性列表是异构的。这意味着一个列表里的元素可以是完全不同的数据类型就像上面的mixed_bag里面同时装了整数、字符串、浮点数和布尔值。这个特性让列表变得极其灵活但同时也要求你在处理列表元素时要格外小心它们的类型。2.2 从其他数据“转化”而来list()构造函数list()是一个内置函数它可以将其他可迭代的对象比如字符串、元组、字典的键等转换成列表。这在数据转换和预处理时非常有用。# 将字符串的每个字符变成列表元素 word Python char_list list(word) # 结果[P, y, t, h, o, n] # 将元组转换为列表元组我们后续课程会讲它类似于不可变的列表 coordinates (10, 20) coord_list list(coordinates) # 结果[10, 20] # 将字典的键或值转换为列表 student {name: Alice, age: 20, grade: A} keys_list list(student.keys()) # 结果[name, age, grade] values_list list(student.values()) # 结果[Alice, 20, A]使用list()进行转换是一种非常清晰的“声明式”编程它明确地告诉阅读代码的人“我在这里意图生成一个新的列表”。2.3 快速生成规律列表列表推导式List Comprehension这是Python中非常强大且优雅的特性也是搜索热词“for if列表表达式”所指的核心内容。它可以用一行代码生成一个列表通常用于对现有序列进行过滤或转换。# 生成一个0到9的平方数列表 squares [x**2 for x in range(10)] # 结果[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 生成一个只包含原列表中偶数的列表 original [1, 2, 3, 4, 5, 6] evens [x for x in original if x % 2 0] # 结果[2, 4, 6] # 结合转换和过滤将列表中所有字符串转换为大写但只保留长度大于3的 words [cat, window, defenestrate] result [word.upper() for word in words if len(word) 3] # 结果[WINDOW, DEFENESTRATE]列表推导式的结构是[表达式 for 变量 in 可迭代对象 if 条件]。它先执行for循环然后用if可选进行过滤最后对每个满足条件的元素执行前面的表达式将所有结果收集成一个新列表。它比传统的for循环append更简洁、执行效率也通常更高是Pythonic代码的标志之一。2.4 重复与拼接*和运算符你可以使用来拼接两个列表使用*来重复一个列表。# 列表拼接 list_a [1, 2, 3] list_b [4, 5, 6] combined list_a list_b # 结果[1, 2, 3, 4, 5, 6] # 列表重复 repeat_list [Hi] * 3 # 结果[Hi, Hi, Hi] zeros [0] * 10 # 快速创建一个包含10个零的列表注意和*运算符都会创建一个新的列表而不是修改原有的列表。list_a和list_b在拼接后本身并没有改变。这是一个需要牢记的点因为它关系到程序的性能和内存使用。3. 与列表交互增删改查的基本功创建了列表之后我们就要和它里面的元素打交道了。这就是常说的“增删改查”CRUD: Create, Read, Update, Delete。这部分操作看似基础但细节很多是日常编码中最频繁使用的部分。3.1 访问元素索引与“越界”陷阱列表中的每个元素都有一个位置编号称为索引Index。在Python中索引从0开始计数。这是编程中的一个通用约定初学者需要花点时间适应。fruits [apple, banana, orange, grape] first_fruit fruits[0] # apple second_fruit fruits[1] # banana third_fruit fruits[2] # orange你还可以使用负索引从列表末尾开始访问元素。-1表示最后一个元素-2表示倒数第二个以此类推。last_fruit fruits[-1] # grape second_last fruits[-2] # orange这里最大的“坑”就是索引越界IndexError。如果你尝试访问一个不存在的索引Python会直接报错。# 以下代码会引发 IndexError: list index out of range # nonexistent fruits[10] # nonexistent fruits[-5]如何避免在访问前可以先检查列表长度。使用内置函数len()可以获取列表包含多少个元素。if len(fruits) 3: print(fruits[3]) # 安全访问 else: print(列表没有第四个元素。)3.2 修改元素直接赋值列表是可变的所以你可以直接通过索引来修改某个位置上的值。fruits [apple, banana, orange, grape] fruits[1] blueberry # 把‘banana’替换成‘blueberry’ print(fruits) # 输出[apple, blueberry, orange, grape]这个操作是“就地in-place”修改列表对象本身的内存地址没有变只是它内部存储的某个引用改变了。3.3 增加元素三种主要方法向列表中添加新元素最常用的有三个方法append(),insert(),extend()。append(item)在列表的末尾添加一个元素。这是最常用、最高效的添加方式因为不需要移动其他元素。numbers [1, 2, 3] numbers.append(4) print(numbers) # 输出[1, 2, 3, 4]insert(index, item)在指定的索引位置插入一个元素。该位置及之后的所有元素都要向右移动一位所以如果在大列表的头部频繁插入性能开销较大。numbers [1, 2, 4] numbers.insert(2, 3) # 在索引2第三个位置插入数字3 print(numbers) # 输出[1, 2, 3, 4]extend(iterable)将另一个可迭代对象如列表、字符串、元组中的所有元素逐个添加到当前列表的末尾。注意它和append()有本质区别。list_a [1, 2] list_b [3, 4] list_a.append(list_b) print(list_a) # 输出[1, 2, [3, 4]] list_b被作为一个整体子列表添加了 list_a [1, 2] # 重置 list_a.extend(list_b) print(list_a) # 输出[1, 2, 3, 4] list_b中的元素被“展开”添加了实操心得90%的情况下当你只是想加一个元素时用append()。当你需要合并两个列表时用extend()或者直接使用运算符会生成新列表extend()修改原列表。insert()要慎用除非你确切的知道要在某个特定位置插入。3.4 删除元素四种方式及其选择删除同样有多种方法选择哪一种取决于你的具体需求。remove(item)删除列表中第一个匹配的指定值的元素。如果值不存在会引发ValueError。fruits [apple, banana, orange, banana] fruits.remove(banana) print(fruits) # 输出[apple, orange, banana]只删除了第一个‘banana’pop([index])删除并返回指定索引位置的元素。如果不提供索引默认删除并返回最后一个元素。如果索引越界引发IndexError。fruits [apple, banana, orange] last_fruit fruits.pop() # 删除‘orange’并返回它 print(last_fruit) # 输出orange print(fruits) # 输出[apple, banana] second_fruit fruits.pop(0) # 删除索引0的元素‘apple’并返回 print(second_fruit) # 输出apple print(fruits) # 输出[banana]del语句这不是一个方法而是一个Python语句。它可以通过索引或切片来删除元素甚至删除整个列表变量。fruits [apple, banana, orange, grape] del fruits[1] # 删除索引为1的元素‘banana’ print(fruits) # 输出[apple, orange, grape] del fruits[0:2] # 使用切片删除前两个元素 print(fruits) # 输出[grape] del fruits # 删除整个列表对象之后如果再访问fruits会报NameError清空列表clear()移除列表中的所有元素使其变成一个空列表。fruits [apple, banana, orange] fruits.clear() print(fruits) # 输出[]如何选择如果你知道要删除的元素的值并且确信它存在用remove()。如果你需要用到被删除的元素比如实现一个栈或队列用pop()。如果你知道要删除元素的索引或者要删除一个切片范围用del语句。如果你想快速清空整个列表用clear()。4. 列表的“高级”操作切片、遍历与成员检查掌握了基本的增删改查你已经可以处理大多数简单任务了。但要真正发挥列表的威力还需要掌握切片、遍历和成员检查这些核心操作。4.1 切片Slicing获取列表的任意子集切片是Python中极其强大和优雅的特性它允许你通过一个简洁的语法list[start:stop:step]来获取列表的一部分一个“子列表”。start起始索引包含。默认为0。stop结束索引不包含。默认为列表长度。step步长即每隔几个元素取一个。默认为1。numbers [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 获取索引2到5不包含5的元素 slice1 numbers[2:5] # 结果[2, 3, 4] # 获取从开头到索引4的元素 slice2 numbers[:4] # 结果[0, 1, 2, 3] # 获取从索引6到末尾的元素 slice3 numbers[6:] # 结果[6, 7, 8, 9] # 获取整个列表的副本浅拷贝后面会讲 copy_of_numbers numbers[:] # 结果[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 使用负索引切片 slice4 numbers[-3:] # 获取最后三个元素结果[7, 8, 9] # 指定步长每隔一个元素取一个 slice5 numbers[::2] # 结果[0, 2, 4, 6, 8] # 步长为负反向获取列表 reverse_copy numbers[::-1] # 结果[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] slice6 numbers[5:2:-1] # 从索引5反向到索引2不包含2结果[5, 4, 3]切片的核心特性切片操作会返回一个新的列表是对原列表部分元素的浅拷贝。修改这个新列表不会影响原列表除非元素本身是可变对象如嵌套列表这是另一个需要注意的“坑”。original [1, 2, 3, 4, 5] sliced original[1:4] # [2, 3, 4] sliced[0] 99 print(sliced) # 输出[99, 3, 4] print(original) # 输出[1, 2, 3, 4, 5] 原列表未变4.2 遍历列表for循环与enumerate遍历或者说迭代是处理列表中每个元素的基本方式。最基本的for循环fruits [apple, banana, orange] for fruit in fruits: print(fI like {fruit}.)需要索引时使用enumerate()enumerate()函数会在迭代时同时返回元素的索引和值非常实用。fruits [apple, banana, orange] for index, fruit in enumerate(fruits): print(fIndex {index} has fruit: {fruit}) # 输出 # Index 0 has fruit: apple # Index 1 has fruit: banana # Index 2 has fruit: orange你还可以指定enumerate()的起始索引for index, fruit in enumerate(fruits, start1): print(fItem {index}: {fruit})使用while循环和索引虽然不常用但在需要更复杂控制循环逻辑时可行。i 0 while i len(fruits): print(fruits[i]) i 14.3 检查元素是否存在in和not in运算符这是一个简单但极其高效的成员检查操作用于判断一个元素是否在列表中。fruits [apple, banana, orange] if banana in fruits: print(Yes, we have bananas!) if grape not in fruits: print(We are out of grapes.)in和not in运算符的背后Python会对列表进行线性搜索。对于非常大的列表频繁的成员检查可能会成为性能瓶颈这时可以考虑使用集合set或字典dict它们基于哈希表实现查找速度接近常数时间。但对于中小型列表或非性能关键场景in运算符的简洁性和可读性是无与伦比的。5. 列表的“内功”常用内置方法与函数Python为列表内置了许多方法通过点号调用如list.append()和函数直接调用如len(list)。熟练使用它们是高效编程的关键。5.1 核心内置方法除了前面提到的增删方法列表还有其他几个非常重要的方法index(item[, start[, end]])返回列表中第一个匹配项的索引。如果找不到引发ValueError。可以指定搜索的起始和结束位置。fruits [apple, banana, orange, banana] idx fruits.index(banana) # 返回 1 idx2 fruits.index(banana, 2) # 从索引2开始找返回 3 # 找不到会报错 # idx3 fruits.index(grape) # ValueError: grape is not in listcount(item)返回元素在列表中出现的次数。fruits [apple, banana, orange, banana] banana_count fruits.count(banana) # 返回 2 grape_count fruits.count(grape) # 返回 0sort(keyNone, reverseFalse)就地对列表进行排序。key参数可以指定一个函数用于从每个元素中提取比较键例如按字符串长度排序。reverse为True时降序排序。numbers [3, 1, 4, 1, 5, 9, 2] numbers.sort() # 升序排序原列表被修改 print(numbers) # 输出[1, 1, 2, 3, 4, 5, 9] numbers.sort(reverseTrue) # 降序排序 print(numbers) # 输出[9, 5, 4, 3, 2, 1, 1] words [apple, fig, banana, cherry] words.sort(keylen) # 按字符串长度排序 print(words) # 输出[fig, apple, cherry, banana] (注意长度相同时相对顺序可能保留)reverse()就地将列表中的元素反向排列。numbers [1, 2, 3] numbers.reverse() print(numbers) # 输出[3, 2, 1]重要区别list.reverse()和list[::-1]或reversed(list)不同。reverse()是原地操作修改原列表。list[::-1]和reversed(list)会生成一个新的反向迭代器或列表不修改原列表。copy()返回列表的一个浅拷贝。与使用切片list[:]效果相同。original [1, 2, [3, 4]] shallow_copy original.copy() shallow_copy[0] 99 shallow_copy[2][0] 88 print(original) # 输出[1, 2, [88, 4]] print(shallow_copy) # 输出[99, 2, [88, 4]]注意浅拷贝的“坑”对于嵌套的可变对象如列表中的列表拷贝的只是引用。修改浅拷贝中的嵌套列表原列表的嵌套列表也会被修改。如果需要完全独立的拷贝需要使用copy模块的deepcopy函数。5.2 关键内置函数len(list)返回列表的长度元素个数。sorted(iterable, keyNone, reverseFalse)返回一个新的已排序列表不修改原列表。参数用法与list.sort()相同。numbers [3, 1, 4] sorted_numbers sorted(numbers) # 返回新列表 [1, 3, 4] print(numbers) # 原列表不变[3, 1, 4]reversed(seq)返回一个反向的迭代器。如果需要列表可以用list()转换。numbers [1, 2, 3] rev_iter reversed(numbers) # 得到一个迭代器对象 rev_list list(rev_iter) # 转换为列表[3, 2, 1]max(list),min(list),sum(list)对数值型列表非常有用。nums [1, 5, 3, 9, 2] print(max(nums)) # 9 print(min(nums)) # 1 print(sum(nums)) # 206. 实战演练从需求到代码的完整过程理论学习之后我们通过几个结合热词的实战例子把知识点串联起来。这些例子都来源于真实的编程需求。6.1 案例一计算列表平均值对应热词“python 计算列表[]中所有元素的平均值”这是一个非常常见的需求比如计算学生成绩的平均分、计算传感器读数的平均值等。需求给定一个数值列表计算其所有元素的平均值。思路分析输入一个包含数字的列表。过程求和然后除以元素个数。输出平均值浮点数。边界情况空列表怎么办非数值列表怎么办代码实现与解析def calculate_average(number_list): 计算数值列表的平均值。 参数: number_list (list): 一个包含数字的列表。 返回: float: 列表的平均值。如果列表为空返回0.0或抛出异常根据业务逻辑决定。 # 首先处理边界情况空列表 if not number_list: # 等价于 if len(number_list) 0: # 这里选择返回0.0也可以选择抛出ValueError取决于你的程序逻辑 return 0.0 # 使用内置函数sum()求和len()求长度 total sum(number_list) count len(number_list) # 计算平均值。注意在Python 3中整数除法会得到浮点数。 average total / count return average # 测试用例 grades [85, 92, 78, 90, 88] avg_grade calculate_average(grades) print(fThe average grade is: {avg_grade:.2f}) # 输出The average grade is: 86.60 # 测试空列表 empty_list [] print(fAverage of empty list: {calculate_average(empty_list)}) # 输出Average of empty list: 0.0 # 测试包含浮点数的列表 temperatures [22.5, 23.1, 21.8, 24.0] avg_temp calculate_average(temperatures) print(fThe average temperature is: {avg_temp:.1f}) # 输出The average temperature is: 22.9避坑指南除以零错误这是最需要警惕的。如果列表可能为空必须在除法操作前进行检查就像我们代码中做的那样。整数除法在Python 2中5 / 2的结果是2整数除法。在Python 3中结果是2.5真除法。我们的代码在Python 3下运行正常。如果你需要兼容Python 2或者明确想要整数结果可以使用//运算符。性能考虑对于非常大的列表sum()和len()都是O(n)复杂度的操作但它们是内置的C语言实现速度非常快通常无需优化。自己写循环求和反而更慢。6.2 案例二使用列表推导式进行数据清洗对应热词“for if列表表达式”数据清洗是数据分析的第一步。假设我们有一个从文件或网络读取的字符串列表里面可能混入了空字符串、无效数据或需要格式化的数据。需求给定一个字符串列表清洗数据1) 移除所有空字符串2) 将所有非空字符串的首字母大写3) 过滤掉长度小于3的字符串。思路分析遍历原列表的每个元素。对每个元素检查是否非空且长度3。如果满足条件则对该元素应用str.capitalize()方法。将所有处理后的结果收集到一个新列表中。列表推导式完美契合这个“过滤-转换-收集”的模式。代码实现与解析raw_data [apple, , banana, cat, , dog, elephant, 123] # 使用列表推导式一步完成清洗 cleaned_data [item.capitalize() for item in raw_data if item.strip() and len(item.strip()) 3] # 分解步骤理解 # 1. for item in raw_data: 遍历原始列表。 # 2. if item.strip() and len(item.strip()) 3: 条件过滤。 # - item.strip(): 移除字符串两端的空白字符包括空格、换行等。 # - if item.strip(): 判断去除空白后是否非空。空字符串去除空白后还是在布尔上下文中为False。 # - len(item.strip()) 3: 判断去除空白后的长度是否大于等于3。 # 3. item.capitalize(): 对满足条件的元素将其首字母大写。 # 4. 最外层的[]: 将所有item.capitalize()的结果收集成一个新列表。 print(f原始数据: {raw_data}) print(f清洗后数据: {cleaned_data}) # 输出 # 原始数据: [apple, , banana, cat, , dog, elephant, 123] # 清洗后数据: [Apple, Banana, Elephant, 123]代码解读与技巧item.strip()是关键。它处理了像 这样的纯空白字符串使其在布尔判断中为False。同时它也清理了数据两端的无用空格。条件if item.strip() and len(item.strip()) 3中item.strip()被计算了两次。对于性能要求极高的场景可以先用一个变量保存它。但对于一般数据量这样写更清晰。注意123被保留了因为它是非空字符串且长度3。capitalize()对数字字符串无效所以它保持不变。这符合我们的需求逻辑。6.3 案例三实现一个简单的任务管理器综合应用让我们用列表构建一个命令行下的简易任务管理器支持添加、查看、标记完成和删除任务。需求分析任务可以用字符串表示。需要记录任务是否完成。核心操作添加、查看所有、查看待办、标记完成、删除。设计思路用列表存储所有任务。每个任务用一个字典表示包含description描述和done是否完成两个字段。通过循环和条件判断实现一个简单的用户交互菜单。代码实现# 初始化一个空的任务列表 tasks [] def show_menu(): 显示功能菜单 print(\n 简易任务管理器 ) print(1. 添加新任务) print(2. 查看所有任务) print(3. 查看待办任务) print(4. 标记任务为完成) print(5. 删除任务) print(0. 退出程序) def add_task(): 添加新任务 description input(请输入任务描述: ).strip() if description: # 防止添加空任务 new_task {description: description, done: False} tasks.append(new_task) print(f任务 {description} 已添加。) else: print(任务描述不能为空) def show_all_tasks(): 显示所有任务 if not tasks: print(当前没有任务。) return print(\n--- 所有任务 ---) for index, task in enumerate(tasks, start1): status ✓ if task[done] else ✗ print(f{index}. [{status}] {task[description]}) def show_pending_tasks(): 显示未完成的任务 pending_tasks [task for task in tasks if not task[done]] # 列表推导式过滤 if not pending_tasks: print(恭喜没有待办任务。) return print(\n--- 待办任务 ---) for index, task in enumerate(pending_tasks, start1): print(f{index}. {task[description]}) def mark_task_done(): 标记任务为完成 show_all_tasks() if not tasks: return try: task_num int(input(请输入要标记为完成的任务编号: )) if 1 task_num len(tasks): tasks[task_num - 1][done] True # 注意索引转换 print(f任务 {tasks[task_num - 1][description]} 已完成) else: print(编号无效) except ValueError: print(请输入有效的数字) def delete_task(): 删除任务 show_all_tasks() if not tasks: return try: task_num int(input(请输入要删除的任务编号: )) if 1 task_num len(tasks): removed_task tasks.pop(task_num - 1) # 使用pop删除并返回被删任务 print(f任务 {removed_task[description]} 已删除。) else: print(编号无效) except ValueError: print(请输入有效的数字) # 主程序循环 def main(): while True: show_menu() choice input(请选择操作 (0-5): ).strip() if choice 1: add_task() elif choice 2: show_all_tasks() elif choice 3: show_pending_tasks() elif choice 4: mark_task_done() elif choice 5: delete_task() elif choice 0: print(感谢使用再见) break else: print(无效选择请重新输入。) # 启动程序 if __name__ __main__: main()项目总结与知识点映射 这个简单的项目几乎用到了我们今天讲的所有核心知识数据结构使用列表tasks作为核心存储容器列表中的每个元素是一个字典。增add_task()函数中使用list.append()方法。删delete_task()函数中使用list.pop(index)方法并处理了用户输入和索引转换。改mark_task_done()函数中通过索引直接修改字典的done字段。查show_all_tasks()遍历整个列表show_pending_tasks()使用列表推导式进行过滤查询。遍历多处使用for index, task in enumerate(tasks, start1)来同时获取索引和任务。成员检查/条件判断在add_task()中使用if description:来检查输入是否为空。列表推导式在show_pending_tasks()中用于过滤出未完成的任务。通过这个实战项目你可以看到列表是如何作为程序核心的数据骨架将各个功能模块串联起来的。理解列表就为你用Python构建更复杂的程序打下了坚实的基础。
返回列表