news 2026/7/4 2:47:54

py learning - day 1(列表、解包)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
py learning - day 1(列表、解包)

1.List的操作

这里需明白sort()和sorted()的区别
前者返回None,对原列表进行排序;后者返回排序后列表,不改变原列表

2.解包

场景 1:基础赋值解包(数量一一对应)
规则:左边有几个变量,右边就必须有几个元素,按顺序一一对应。

底层机制:Python 虚拟机(CEVAL)直接通过 UNPACK_SEQUENCE 字节码将栈顶的序列按索引直接映射到变量,无需创建中间容器。

时间复杂度:O(1)(常数级)。无论解包 3 个还是 5 个元素,只要数量固定,消耗的指令条数是恒定的。

# 示例 1.1:拆列表a,b,c=[1,2,3]print(a)# 输出: 1print(b)# 输出: 2print(c)# 输出: 3# 示例 1.2:拆字符串(字符串也是排队对象)x,y,z="ABC"print(x)# 输出: Aprint(y)# 输出: Bprint(z)# 输出: C在这里插入代码片

场景 2:扩展解包(使用 * 星号,吸收多余的元素)
规则:带 * 的变量会变成一个“大胃王”,把剩下的所有元素打包成一个列表吞掉。

底层机制:Python 必须先遍历右侧的可迭代对象,计算出总数,然后将未被单独匹配的元素显式创建为一个新的列表(List) 赋给带星号的变量。

时间复杂度:O(K),其中 K 是赋给带星号变量的元素数量。因为底层必须将这部分元素从源迭代器中拷贝到新的内存空间中(本质是 list_extend 操作)。如果源是生成器,解包会强制将其完全消耗(Exhaust),这也是 O(N)。

# 示例 2.1:吸收中间或尾部head,*tail=[10,20,30,40]print(head)# 输出: 10(第一个元素)print(tail)# 输出: [20, 30, 40](剩下的全变成列表)# 示例 2.2:取第一个和最后一个,中间全打包first,*middle,last=[1,2,3,4,5]print(first)# 输出: 1print(middle)# 输出: [2, 3, 4](注意,中间被打包成列表)print(last)# 输出: 5# 示例 2.3:如果右边是空列表,星号变量会变成空列表a,*b=[100]print(a)# 输出: 100print(b)# 输出: [](没东西可吃,就是个空列表)在这里插入代码片

场景 3:函数调用解包(* 拆列表给位置参数,拆字典给关键字参数)
规则:把列表拆成“一个个单独的值”喂给函数;把字典拆成“键=值”的形式喂给函数。
底层机制:
* 解包:CPython 通过 PyObject_GetIter 获取迭代器,然后循环调用 PyIter_Next 将每个元素压入调用栈(Call Stack)中。

** 解包:底层调用 PyDict_Next 遍历字典,将键值对映射为关键字参数。

时间复杂度:O(N),其中 N 是被解包的元素/键值对数量。因为参数需要逐个被读取并压栈。

# 3.1 定义一个需要三个参数的函数defintroduce(name,age,city):returnf"姓名:{name}, 年龄:{age}, 城市:{city}"# ----- 使用 * 拆列表(按顺序对应)-----person_list=["张三",18,"北京"]result1=introduce(*person_list)# 相当于执行 introduce("张三", 18, "北京")print(result1)# 输出: 姓名: 张三, 年龄: 18, 城市: 北京# ----- 使用 ** 拆字典(按键名对应)-----person_dict={"city":"上海","name":"李四","age":20}# 注意:顺序可以乱,因为按名字匹配result2=introduce(**person_dict)# 相当于执行 introduce(city="上海", name="李四", age=20)print(result2)# 输出: 姓名: 李四, 年龄: 20, 城市: 上海# 额外演示:如果直接把字典传进去,不解包,会报错!# introduce(person_dict) # 报错:因为只传了1个参数,但函数要3个

场景 4:容器合并解包(拼凑新列表 / 新字典)
规则:把几个盒子里的东西全部倒出来,放进一个新盒子里。

底层机制:CPython 会预计算总长度,然后对每个元素执行一次插入(字典则是哈希映射)操作。

时间复杂度:O(M + N),其中 M 和 N 分别是两个容器的长度。每解包一个元素,底层就进行一次 C 级的内存拷贝(memcpy)或哈希插入。

# 4.1 合并两个列表(用 *)list_a=[1,2]list_b=[3,4]combined_list=[*list_a,*list_b,5,6]# 把两个列表和额外数字全拆开合并print(combined_list)# 输出: [1, 2, 3, 4, 5, 6]# 4.2 合并两个字典(用 **)dict_a={"name":"王五","age":25}dict_b={"city":"广州","job":"工程师"}merged_dict={**dict_a,**dict_b}# 把两本字典的内容抄进新字典print(merged_dict)# 输出: {'name': '王五', 'age': 25, 'city': '广州', 'job': '工程师'}# 4.3 如果两个字典有相同的键,后面的会覆盖前面的d1={"a":1,"b":2}d2={"b":999,"c":3}print({**d1,**d2})# 输出: {'a': 1, 'b': 999, 'c': 3} (b被覆盖了)

致命的错误:

虽然解包是 O(N),但有一种情况极端危险:

切勿在函数参数中混合使用多次大规模解包,例如:func(*list1, *list2, *list3)

在 Python 3.5+ 中这是合法的语法,但底层并不会一次性合并再传参。

它会依次遍历 list1,压栈;再遍历 list2,压栈;再遍历 list3,压栈。

如果这三个列表总大小为 1000 万,虽然最终复杂度依然是 O(N),但传参过程会将所有参数全部压入栈帧(Frame)中。这会导致极高的内存占用r,且传递大列表时,解包速度远慢于直接传递列表本身。

详细原因:
你要先理解 Python 函数调用时,参数在底层是怎么存放的。

直接传递列表:func(list1)
底层只做一件事:把 list1 的“门牌号(内存地址)”压入栈帧。
无论 list1 里有 1 个还是 1 亿个元素,压进去的都只是一个地址(占用 8 个字节)。
空间复杂度 = O(1)(常数级)。

解包传递:func(*list1, *list2, *list3)
底层必须做三件事(CPython 源码 call.c 中的逻辑):

计算总长度:算出 len(list1) + len(list2) + len(list3)。
申请新内存:在 C 层调用 PyTuple_New(total_length),创建一个能装下所有元素的巨型元组(Tuple)。
拷贝指针:用循环把 list1、list2、list3 里的每一个元素的指针,逐个拷贝进这个新元组里。
关键点:虽然拷贝的是指针(不是数据本身),但 1000 万个指针占用 8字节 * 1000万 = 80 MB 内存。再加上元组本身的开销,瞬间多出近百 MB 的额外消耗。更可怕的是,这 80 MB 必须是一块连续的内存空间(类似于数组),如果内存碎片化,申请失败直接报 MemoryError。

解决方法:

场景推荐做法原因
拼接多个小列表(总长 < 1万)放心用func(*a, *b, *c)优雅、简洁,C 级速度极快,损耗忽略不计。
拼接超大列表(总长 > 10万)绝对禁止func(*a, *b, *c)内存翻倍 + 遍历拷贝,性能雪崩。
需要合并超大列表再处理改为func(a + b + c)(列表拼接)虽然也会新建列表,但比解包压栈少一层元组转换,稍好一点。
极致的性能要求(百万级)直接传三个独立列表:func(a, b, c),在函数内部用for循环遍历 a、b、c空间 O(1),时间仅遍历 1 次,这是最优解。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/29 1:54:43

计算机Java毕设实战-基于 SpringBoot+Vue 的校园竞赛项目信息管理系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/29 10:39:23

VASP GW+BSE计算激子和可视化

本教程介绍基于VASP的 的完整 BSE 计算流程&#xff1a;以单层 MoSe2为例&#xff0c;从基态自洽场出发&#xff0c;经 GW 准粒子修正至 BSE 激子求解&#xff0c;最终通过VaspBandUnfolding的 bseplot 功能实现倒空间与实空间激子可视化。涵盖 INCAR 参数详解、关键文件生成逻…

作者头像 李华
网站建设 2026/6/29 10:42:09

儿童救生衣推荐|家长选购必看!欧盟 CE 认证救生衣选购科普

每到夏季&#xff0c;水上乐园、内河漂流、近海游船、亲子桨板成为热门家庭出游项目&#xff0c;儿童水上安全问题备受家长重视。不少家长挑选浮力装备时十分困惑&#xff1a;成人浮力衣缩小版能给孩子穿吗&#xff1f;什么样的儿童救生衣具备可靠安全资质&#xff1f;今天带大…

作者头像 李华
网站建设 2026/6/29 1:02:24

EESHEEEP APD偏置电路

TI 用LM2733XMF设计用于雪崩光电二极管&#xff08;APD&#xff09;的高升压比偏置电源 ZHCA769

作者头像 李华