查看: 210|回复: 3

Python列表推导式与切片进阶:高阶函数、嵌套拷贝与避坑

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
列表是Python中最常用的可变序列类型,基础增删改查之外,推导式、切片、高阶函数和嵌套结构处理更能决定代码是否简洁、稳定。下面围绕这些用法给出可直接运行的示例,并说明容易踩坑的细节。

一、列表推导式:用一行表达式生成列表
列表推导式的基本形式是[表达式 for 元素 in 可迭代对象],带条件时写成[表达式 for 元素 in 可迭代对象 if 条件判断]。它把循环和条件判断压缩到一行,在编译层面减少了append等函数调用,效率通常比普通for循环高20%-50%。
  1. square_list = [i ** 2 for i in range(1, 11)]
  2. print(square_list)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
  3. even_list = [i for i in range(1, 21) if i % 2 == 0]
  4. print(even_list)  # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
  5. num_list = [i for i in range(1, 101) if i % 3 == 0 and i % 5 == 0]
  6. print(num_list)  # [15, 30, 45, 60, 75, 90]
  7. two_d_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
  8. flat_list = [num for sublist in two_d_list for num in sublist]
  9. print(flat_list)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]
  10. even_flat_list = [num for sublist in two_d_list for num in sublist if num % 2 == 0]
  11. print(even_flat_list)  # [2, 4, 6, 8]
复制代码
嵌套推导式适合把二维列表扁平化,也适合在多层循环中直接带条件筛选。数据量较大时,优先考虑推导式而不是先建空列表再循环append。

二、切片进阶:步长、逆序和切片赋值
切片完整语法是list[start:end:step]。start默认0,end默认列表长度且不包含end本身,step默认1,可为正负;step为0会抛出ValueError。切片返回的是列表的浅拷贝,修改切片结果本身不会影响原列表;start或end超出索引范围时不会报错,只会取到列表边界。
  1. lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  2. print(lst[::2])  # [0, 2, 4, 6, 8]
  3. print(lst[1::3])  # [1, 4, 7]
  4. print(lst[::-1])  # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
  5. print(lst[5:2:-1])  # [5, 4, 3]
  6. lst = [1, 2, 3, 4, 5]
  7. lst[1:4] = [10, 20, 30]
  8. print(lst)  # [1, 10, 20, 30, 5]
  9. del lst[2:5]
  10. print(lst)  # [1, 10]
  11. lst[1:1] = [5, 6, 7]
  12. print(lst)  # [1, 5, 6, 7, 10]
复制代码
切片赋值可以批量替换元素,并且允许赋值长度与原切片长度不一致,列表会自动调整长度;空切片赋值则可以完成插入操作。

三、map、filter、reduce与列表配合
map把函数应用到每个元素上,filter保留判断结果为True的元素,二者返回迭代器,通常需要用list转换。reduce用于从左到右累积计算,Python3中需要从functools导入。
  1. num_list = [1, 2, 3, 4, 5]
  2. str_list = list(map(str, num_list))
  3. print(str_list)  # ['1', '2', '3', '4', '5']
  4. square_list = list(map(lambda x: x ** 2, num_list))
  5. print(square_list)  # [1, 4, 9, 16, 25]
  6. list1 = [1, 2, 3]
  7. list2 = [4, 5, 6]
  8. sum_list = list(map(lambda x, y: x + y, list1, list2))
  9. print(sum_list)  # [5, 7, 9]
  10. num_list = [-2, -1, 0, 1, 2, 3]
  11. positive_list = list(filter(lambda x: x > 0, num_list))
  12. print(positive_list)  # [1, 2, 3]
  13. str_list = ['a', '', 'b', None, 'c', ' ']
  14. non_empty_list = list(filter(lambda x: x and x.strip(), str_list))
  15. print(non_empty_list)  # ['a', 'b', 'c']
  16. from functools import reduce
  17. num_list = [1, 2, 3, 4, 5]
  18. total = reduce(lambda x, y: x + y, num_list)
  19. print(total)  # 15
  20. product = reduce(lambda x, y: x * y, num_list)
  21. print(product)  # 120
  22. total_with_init = reduce(lambda x, y: x + y, num_list, 10)
  23. print(total_with_init)  # 25
复制代码
多列表映射时,map可以接收多个可迭代对象;reduce带初始值时,会先把初始值加入累积过程。

四、嵌套列表:遍历、推导式与深浅拷贝
嵌套列表可以用双层for循环遍历,也可以用推导式生成新结构。真正需要警惕的是拷贝:切片和copy()只拷贝外层,内层列表仍是引用;copy.deepcopy()才会连内外层一起复制。
  1. import copy
  2. two_d_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
  3. new_list = [[num * 2 for num in sublist] for sublist in two_d_list]
  4. print(new_list)  # [[2, 4, 6], [8, 10, 12], [14, 16, 18]]
  5. shallow_copy = two_d_list[:]
  6. shallow_copy[0][0] = 100
  7. print(two_d_list)  # [[100, 2, 3], [4, 5, 6], [7, 8, 9]]
  8. deep_copy = copy.deepcopy(two_d_list)
  9. deep_copy[0][0] = 200
  10. print(two_d_list)  # [[100, 2, 3], [4, 5, 6], [7, 8, 9]]
  11. print(deep_copy)  # [[200, 2, 3], [4, 5, 6], [7, 8, 9]]
复制代码
浅拷贝后修改内层元素会影响原列表,这是嵌套结构中最容易误判的行为;需要完全独立的数据时,应使用deepcopy。

五、去重、排序和高效拼接
set去重效率高但不保证原顺序;dict.fromkeys()在Python3.7+可保持原顺序。sort()是原地排序,sorted()返回新列表,二者都支持自定义key函数。频繁用+拼接列表会不断生成新列表,批量扩展更推荐extend()。
  1. lst = [2, 1, 3, 2, 4, 1, 5, 3]
  2. unique_list1 = list(set(lst))
  3. print(unique_list1)  # 顺序可能变化
  4. unique_list2 = list(dict.fromkeys(lst))
  5. print(unique_list2)  # [2, 1, 3, 4, 5]
  6. str_list = ['apple', 'banana', 'cherry', 'date']
  7. str_list.sort(key=len)
  8. print(str_list)  # ['date', 'apple', 'banana', 'cherry']
  9. tuple_list = [(1, 3), (2, 1), (3, 2)]
  10. sorted_list = sorted(tuple_list, key=lambda x: x[1])
  11. print(sorted_list)  # [(2, 1), (3, 2), (1, 3)]
  12. dict_list = [{'name': 'Alice', 'age': 28}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 30}]
  13. dict_list.sort(key=lambda x: x['age'], reverse=True)
  14. print(dict_list)  # [{'name': 'Charlie', 'age': 30}, {'name': 'Alice', 'age': 28}, {'name': 'Bob', 'age': 25}]
  15. lst1 = [1, 2, 3]
  16. lst2 = [4, 5, 6]
  17. lst1.extend(lst2)
  18. print(lst1)  # [1, 2, 3, 4, 5, 6]
  19. lst = [1, 2, 3]
  20. lst.extend([0] * 5)
  21. print(lst)  # [1, 2, 3, 0, 0, 0, 0, 0]
复制代码
按字符串长度排序、按元组第二个元素排序、按字典某个键排序,都是key函数的典型场景;reverse=True用于降序。

六、常见坑点与避坑方式
第一个坑是列表作为函数默认参数。列表是可变对象,默认参数会被缓存,多次调用会累积修改。正确做法是用None作为默认值,在函数内部再创建新列表。
  1. def add_item_bad(item, lst=[]):
  2.     lst.append(item)
  3.     return lst
  4. print(add_item_bad(1))  # [1]
  5. print(add_item_bad(2))  # [1, 2]  # 默认列表被复用
  6. def add_item(item, lst=None):
  7.     if lst is None:
  8.         lst = []
  9.     lst.append(item)
  10.     return lst
  11. print(add_item(1))  # [1]
  12. print(add_item(2))  # [2]
复制代码
第二个坑是遍历列表时直接删除元素,索引会错位,可能漏删。可以遍历列表拷贝,或者倒序遍历删除。
  1. lst = [1, 2, 3, 4, 5]
  2. for num in lst.copy():
  3.     if num % 2 == 0:
  4.         lst.remove(num)
  5. print(lst)  # [1, 3, 5]
  6. lst = [1, 2, 3, 4, 5]
  7. for i in range(len(lst) - 1, -1, -1):
  8.     if lst[i] % 2 == 0:
  9.         lst.pop(i)
  10. print(lst)  # [1, 3, 5]
复制代码
第三个坑是浅拷贝与深拷贝混用。嵌套列表用切片或copy()后,内层仍是引用;修改内层会反向影响原数据。需要独立副本时使用deepcopy。

七、使用建议
大规模数据生成优先用列表推导式,批量元素处理用map/filter,累积计算用reduce,嵌套列表注意深浅拷贝差异;频繁拼接列表时避免反复使用+,优先extend()。把这些用法和坑点落实到日常脚本、数据处理和业务代码中,列表的简洁性和执行效率才能真正发挥出来。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python列表推导式与切片进阶:高阶函数、嵌套拷贝与避坑

这篇整理得很系统,例子也都能直接跑,收藏了。几个点我平时也深有体会:列表推导式在数据量大的时候确实比先建空列表再 append 快不少,尤其是带条件过滤的场景,写起来也清爽;多列表 map 那块很实用,之前处理两列数据对齐就是这么干的,比 for 循环配对省事。 切片赋值那段讲得很清楚,我刚开始学的时候一直以为切片赋值的长度必须和原切片一致,后来才发现可以自动伸缩,空切片插入更是解决问题的一把好手。还有 step 为负时 end 不包含这一点,经常写反。 最后嵌套列表的浅拷贝坑太真实了,切片和 copy 只复制外层,改内层会连带原列表一起变,刚接触时被这个坑过好几次,排查半天才定位到。帖子末尾似乎没贴完 deepcopy 的示例,方便的话可以补上,正好和浅拷贝对照着看更直观。另外嵌套推导式虽然方便,但层数多了可读性会下降,我一般两层就收手,再多就拆成普通循环加注释了。整体内容很扎实,感谢分享。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python列表推导式与切片进阶:高阶函数、嵌套拷贝与避坑

这篇总结挺系统的,推导式、切片、map/filter/reduce 和嵌套列表拷贝这几个点都覆盖到了,示例也直观,方便对照理解。尤其切片赋值允许长度不一致、空切片插入,以及浅拷贝后修改内层会影响原列表这些坑,写得很实用。浅拷贝例子后面如果能再补一个 deepcopy 的对照,把内外层都复制后的效果展示出来,整个拷贝部分会更完整。整体看很适合当速查和避坑笔记。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python列表推导式与切片进阶:高阶函数、嵌套拷贝与避坑

这篇整理挺扎实的,推导式、切片赋值、map/filter/reduce 和嵌套拷贝这些点都串起来了,尤其深浅拷贝那段很实用。用切片做浅拷贝后,改 shallow_copy[0][0] 会连带原列表一起变,这个坑确实很常见,后面如果补一个 copy.deepcopy 的对比就更完整了。 另外有两个小提醒:切片赋值时如果步长不是 1,右侧长度通常要和被替换的切片长度一致,不然容易报错;map 和 filter 返回的是迭代器,遍历一次就消费掉了,需要反复用的时候记得先转成列表。推导式在简单场景下确实简洁高效,但嵌套层级太深时也别硬压成一行,可读性还是很重要。整体内容很适合拿来查漏补缺。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-1 07:24 , Processed in 0.029940 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部