学到列表、元组、字典、集合之后,很多人会有一种错觉。
好像每种容器学完就结束了。 列表是列表,元组是元组,字典是字典,集合是集合。 各写各的,互不相干。
但真实写代码时,你很快就会发现,真正高频的操作,往往不是只用一种容器,而是在不同容器之间来回切换。
比如:
原始数据是列表,但你想去重,于是转成集合 数据本来是元组,但你临时要修改,于是先转成列表 接口返回的是字典,但你只想拿它的键,转成列表更方便处理 有两列数据想组成键值对,就要转成字典
这就是容器转换的意义。
如果说前面几章是在认识每种工具, 那么这一章,就是开始学会在不同工具之间切换。
很多数据处理能力,恰恰就体现在这个切换过程里。
一、为什么一定要学容器转换
先说一句很实在的话。
现实里的数据,通常不会乖乖地按你最想要的形式出现。 你拿到它时,往往只是某种原始状态。
比如你拿到的是一个列表,但里面有重复项。 比如你拿到的是一个元组,但接下来你想改其中某个值。 比如你拿到的是一个字典,但你只关心所有的值。 比如你拿到的是一组二元数据,想把它们变成键值对。
这时候,最自然的做法不是硬着头皮用原容器死磕,而是先转换,再处理。
真正顺手的代码,很多时候不是一条路走到黑,而是:
先把数据变成更适合当前任务的形状,再下手。
这就是容器转换的核心思维。
二、Python 里最常见的几个转换函数
容器转换最常见的就是这几个内置函数:
list()tuple()set()dict()
它们的名字都很直白。
list() 把数据转成列表tuple() 把数据转成元组set() 把数据转成集合dict() 把数据转成字典
你可以把它们理解成四个转换器。
传进去一种数据,出来另一种容器。
当然,不是所有数据都能随便互转。 能不能转,取决于原数据本身长什么样。 但大方向就是这么回事。
三、转成列表:list() 是最常用的入口之一
很多时候,列表像一个中转站。
因为列表可修改、可遍历、可切片,操作非常灵活。 所以不少数据在处理前,都会先转成列表。
先看最简单的例子,把元组转成列表:
nums = (10, 20, 30)result = list(nums)print(result)print(type(result))
输出:
[10, 20, 30]<class 'list'>
这时候你就从一个不能改的元组,变成了一个能改的列表。
再看集合转列表:
s = {1, 2, 3, 4}result = list(s)print(result)print(type(result))
输出会是一个列表,不过顺序不一定固定。
这一点很重要。 因为集合本来就是无序的,所以转成列表后,只是变成了列表类型,并不代表顺序就 magically 变得有规律了。
再看字符串转列表:
text = 'python'result = list(text)print(result)
输出:
['p', 'y', 't', 'h', 'o', 'n']
也就是说,字符串转列表时,会按字符一个个拆开。
这个用法在文本处理里很常见。
四、转成元组:tuple() 适合把数据固定下来
元组最大的特点,是不可变。
所以把数据转成元组,很多时候不是为了功能更多,而是为了让它稳定下来。
比如列表转元组:
nums = [10, 20, 30]result = tuple(nums)print(result)print(type(result))
输出:
(10, 20, 30)<class 'tuple'>
这在什么情况下有用?
比如你有一组数据,最开始需要修改,所以用列表处理。 但处理完成后,你希望它作为最终结果保持不变,那就可以转成元组。
再比如集合转元组:
s = {1, 2, 3}result = tuple(s)print(result)
一样能转,但顺序仍然不保证。
你要慢慢形成一个意识:
从无序容器转到有序外表的容器时,类型变了,不代表顺序逻辑就自动稳定了。
五、转成集合:set() 是去重神器
这几乎是集合最常见的出场方式。
比如一个列表里有重复元素:
nums = [1, 2, 2, 3, 4, 4, 5]result = set(nums)print(result)
输出:
{1, 2, 3, 4, 5}
重复项自动没了。
这就是为什么很多人一提到去重,第一反应就是:
先 set()
再看元组转集合:
nums = (10, 20, 20, 30)result = set(nums)print(result)
一样可以去重。
再看字符串转集合:
text = 'banana'result = set(text)print(result)
输出会是由不同字符组成的集合,比如:
{'b', 'a', 'n'}
这个在字符去重、标签去重、名单去重时都非常实用。
但你一定要记住一个代价:
转成集合之后,顺序通常就丢了。
所以 set() 很适合去重, 但如果你既想去重,又很在意原顺序,就不能只靠这一招。
六、转成字典:dict() 不是随便什么都能转
前面三个转换相对直观,dict() 稍微特殊一点。
因为字典不是一排值,而是键值对结构。 所以你想转成字典,原数据必须长得像 一组一组的成对数据。
比如这种就可以:
data = [('name', '张三'), ('age', 18), ('score', 95)]result = dict(data)print(result)
输出:
{'name': '张三', 'age': 18, 'score': 95}
这里列表里的每个元素,本身又是一个二元结构。 前面当键,后面当值,刚好能拼成字典。
元组套元组也可以:
data = (('name', '李四'), ('age', 20))result = dict(data)print(result)
也是一样的道理。
但如果你这样写:
data = [1, 2, 3]result = dict(data)
就会报错。
因为 dict() 根本不知道哪个该当键,哪个该当值。
所以关于 dict(),你先记住一句特别重要的话:
不是所有容器都能直接转字典, 只有像一组组 键值对 的数据,才适合转。
七、最常见的几种转换关系,先整体过一遍
为了让你脑子里有张图,我们先把最常见的转换关系说清楚。
列表、元组、集合,这三者之间经常互转。 因为它们本质上都像是一组元素的集合,只是特性不同。
比如:
list(tuple数据)tuple(list数据)set(list数据)list(set数据)tuple(set数据)
这些都很常见。
字典则稍微特殊。
字典可以转成列表、元组、集合,但默认转出去的是键。 而别的容器想转成字典,必须满足 键值对结构。
这个点特别关键,后面我们详细展开。
八、列表转元组:把可变变成不可变
这个场景非常典型。
比如你先用列表接收和整理数据:
data = [100, 200, 300]
中途你做了一些处理,最后你希望结果固定下来,不再被误改:
final_data = tuple(data)print(final_data)
这时候得到的就是元组。
这种思路在项目里挺常见:
处理中,用列表 定稿后,用元组
你可以把它理解成:
草稿阶段灵活改 最终版本固定住
九、元组转列表:为了修改,先拆开再动手
这也是一个高频场景。
前面我们学元组时说过,它不能直接改。 如果你确实要改,那最稳的方式就是先转列表。
nums = (10, 20, 30)temp = list(nums)temp[1] = 200nums = tuple(temp)print(nums)
输出:
(10, 200, 30)
这个流程你一定要熟:
元组 先转列表 修改 再按需要转回元组
这其实就是一种非常实用的处理套路。
十、列表转集合:最经典的去重操作
这招太常用了,值得单独再讲一次。
names = ['张三', '李四', '张三', '王五', '李四']unique_names = set(names)print(unique_names)
你会发现,很多本来需要循环判断的事情,集合一句就解决了。
但如果你后面还需要列表形式继续处理,就可以再转回来:
names = ['张三', '李四', '张三', '王五', '李四']unique_names = list(set(names))print(unique_names)
这时候结果是列表,但顺序不一定和原始数据一致。
所以这招适合:
你更在乎去重结果 不太在意原顺序
十一、集合转列表:为了排序、切片、展示
集合虽然适合去重和成员判断,但它不支持索引,也不支持切片。 所以很多时候,集合处理完之后,还会再转回列表,方便后续操作。
比如:
s = {'Python', 'Java', 'Go'}result = list(s)print(result)
转成列表后,你就可以做列表能做的事情了。 比如排序:
langs = {'Python', 'Java', 'Go'}result = list(langs)result.sort()print(result)
这在展示数据时很常见。
先用集合去重 再转成列表排序 最后输出
这个流程非常像真实项目中的数据整理过程。
十二、字符串和容器之间的转换,也非常常见
虽然这一章重点是容器之间转换,但字符串和容器的关系也特别紧密,顺手一起讲清楚更实用。
先看字符串转列表:
text = 'hello'print(list(text))
结果是按字符拆开。
字符串转元组也一样:
text = 'hello'print(tuple(text))
字符串转集合,则会去掉重复字符:
text = 'hello'print(set(text))
得到的大概是:
{'h', 'e', 'l', 'o'}
这在处理文本、统计字符、去重字符时特别有用。
反过来,列表也能转回字符串,但不能直接用 str(list) 来当真正的拼接。 更常见的是用 join(),这个你后面的字符串章节会系统学到。
这里只先建立一个意识:
字符串和容器之间,经常也会来回转换。 这在文本处理里非常高频。
十三、字典转列表,到底会得到什么
这个问题是很多新手第一次碰到时最容易懵的。
先看代码:
student = {'name': '张三','age': 18,'score': 95}result = list(student)print(result)
输出:
['name', 'age', 'score']
注意,转出来的是键,不是值,也不是整组键值对。
为什么?
因为字典默认遍历的就是键。list(dict对象) 本质上就相当于把它遍历一遍,所以拿到的是所有键。
这一点非常重要。
很多人以为会得到:
['张三', 18, 95]
其实不会。
默认只会拿键。
十四、如果我想拿字典的值,该怎么转
那就不能直接 list(student) 了,而要显式写 values()。
student = {'name': '张三','age': 18,'score': 95}result = list(student.values())print(result)
输出:
['张三', 18, 95]
这才是值列表。
同理,如果你想拿键列表,可以写得更明确一点:
result = list(student.keys())print(result)
虽然 list(student) 也能拿键,但 list(student.keys()) 更清楚。
十五、如果我想拿字典的键值对呢
那就用 items()。
student = {'name': '张三','age': 18,'score': 95}result = list(student.items())print(result)
输出:
[('name', '张三'), ('age', 18), ('score', 95)]
这个结果特别有价值。
因为它已经变成了一个由二元元组组成的列表。 而这种结构,既方便遍历,也方便再转回字典。
你会发现,这就是容器之间互通的关键。
字典 通过 items()变成一组二元数据 又可以再被 dict() 吃回去
这套思路在数据整理时非常常见。
十六、字典和集合互转,要格外小心
严格来说,字典和集合不是那种最自然的一对。
如果你直接这样写:
student = {'name': '张三','age': 18}result = set(student)print(result)
得到的是键集合:
{'name', 'age'}
因为字典默认还是按键来遍历。
如果你想把值转集合,就得写:
result = set(student.values())print(result)
如果你想把键值对转集合,可以写:
result = set(student.items())print(result)
但要注意,items() 转成集合时,前提是这些键值对本身必须能作为集合元素存在。 常规情况下问题不大,但如果值里有列表这类可变对象,就会出问题。
所以这一块先记住大原则:
字典默认转别的容器,优先是拿键。 想拿值或键值对,要显式写出来。
十七、dict() 的两个典型来源
dict() 最常见的来源,基本就两类。
第一类,是一组二元数据。
data = [('a', 1), ('b', 2), ('c', 3)]result = dict(data)print(result)
第二类,是关键字参数形式。
result = dict(name='张三', age=18, score=95)print(result)
输出:
{'name': '张三', 'age': 18, 'score': 95}
这一招平时也能见到,但你自己写业务代码时,更常见的还是第一种,也就是由二元结构转字典。
十八、重复数据在转换时会发生什么
这部分很容易被忽略,但非常实用。
先看列表转集合。
nums = [1, 2, 2, 3, 3, 3]print(set(nums))
重复会被自动去掉。
再看二元数据转字典:
data = [('name', '张三'), ('age', 18), ('name', '李四')]print(dict(data))
输出:
{'name': '李四', 'age': 18}
你会发现,重复键会被后面的值覆盖。
这和前面学字典时的规则是一样的:键不能重复,后面的会顶掉前面的。
所以转换不是简单换个壳,它还可能顺带改变数据本身的表现形式。
去重、覆盖、顺序变化,这些都要有心理准备。
十九、顺序问题,是转换里最容易被忽略的坑
这一节你一定要认真看。
很多新手转换容器时,最容易默认一个想法:
值没变,那顺序应该也差不多吧。
其实不一定。
尤其是只要中间经过了集合,顺序就很可能发生变化。
比如:
nums = [3, 1, 2, 3, 2]result = list(set(nums))print(result)
你得到的是一个去重后的列表,但顺序通常不再可靠。
所以这类写法很适合粗去重, 不适合那种既要去重又要保持原有先后关系的业务。
这一点非常关键。
以后你一旦写出 set(),脑子里就要自动响起一个提醒:
顺序可能没了。
二十、一个真实感很强的案例:名单去重后再排序
假设你有一份报名名单:
names = ['张三', '李四', '张三', '王五', '李四', '赵六']
你想做三件事:
先去重 再排序 最后展示
代码就可以这样写:
names = ['张三', '李四', '张三', '王五', '李四', '赵六']result = list(set(names))result.sort()print(result)
这里其实就完成了三步转换思维:
原始列表 转集合去重 再转列表排序
这就是容器转换在真实处理流程里的样子。
二十一、再看一个案例:元组数据修改后再固定
假设你有一份商品配置:
config = ('机械键盘', 299, '黑色')
现在你临时要把价格改成 279。 元组不能直接改,那怎么办?
config = ('机械键盘', 299, '黑色')temp = list(config)temp[1] = 279config = tuple(temp)print(config)
这就是典型的:
元组 → 列表 → 修改 → 元组
你以后碰到不可变对象想调整,第一反应就可以是这个流程。
二十二、再看一个案例:两列数据拼成字典
假设你手里有这样的数据:
data = [('语文', 95), ('数学', 98), ('英语', 93)]
现在你想把它变成更清晰的字典形式:
scores = dict(data)print(scores)
输出:
{'语文': 95, '数学': 98, '英语': 93}
你会发现,一旦转成字典,后面按科目取分数就舒服多了:
print(scores['数学'])
这就是为什么说,容器转换不是花活,而是为了让后续处理更顺手。
二十三、最常见的几个误区,提前帮你避坑
第一个误区,是以为 list(dict) 会拿到字典的值。 其实默认拿到的是键。
第二个误区,是以为 set() 去重后还能保留原顺序。 多数情况下别这么想。
第三个误区,是以为 dict() 什么都能转。 其实只有类似 键值对 的数据才能顺利转。
第四个误区,是以为转成另一种容器后,原容器会跟着变化。 不会。 转换通常是生成一个新容器,不是原地变形。
比如:
nums = [1, 2, 3]result = tuple(nums)print(nums)print(result)
原列表还是原列表,元组是新生成的结果。
第五个误区,是忽略了重复键覆盖问题。dict() 遇到重复键时,后面的值会覆盖前面的值,这一点一定要留意。
二十四、什么时候该主动想到转换
这个问题非常实战。
以后你写代码时,如果出现下面这些需求,脑子里就应该主动想到转换。
想去重 想到 set()
想修改元组 想到先 list()
想把结果固定下来 想到 tuple()
想让一组二元数据更好查找 想到 dict()
想从字典里拿出键、值、键值对继续批量处理 想到 keys()、values()、items() 再配合 list()、set()、tuple()
你会发现,很多操作一旦和转换结合起来,代码立刻就顺了。
二十五、练习题:把这一章真正练熟
下面这些小题,建议你自己动手敲。
1. 把列表转成元组
nums = [1, 2, 3, 4]result = tuple(nums)print(result)
2. 把元组转成列表,并把第二个元素改掉
nums = (10, 20, 30)temp = list(nums)temp[1] = 200print(temp)
3. 把列表去重后转成集合
nums = [1, 2, 2, 3, 4, 4]result = set(nums)print(result)
4. 把集合转成列表后排序
s = {5, 2, 8, 1}result = list(s)result.sort()print(result)
5. 把一组二元数据转成字典
data = [('name', '张三'), ('age', 18), ('score', 95)]result = dict(data)print(result)
6. 分别把字典的键、值、键值对转成列表
student = {'name': '张三','age': 18,'score': 95}print(list(student.keys()))print(list(student.values()))print(list(student.items()))
这些题不难,但特别有代表性。 你只要自己敲一遍,容器转换这件事就不再是抽象概念,而会变成手上的真实能力。
二十六、本章小结
这一章最重要的,不是背下四个转换函数,而是建立一种处理数据的新思路。
很多时候,问题并不难。 难的是你拿着不合适的容器,硬做本该轻松的事。
列表、元组、集合这三者之间,经常可以互相转换。 字典稍微特殊一些,默认转出去的是键,转进来则要求原数据像键值对。 而一旦中间经过集合,你就要格外留意顺序问题。 一旦转成字典,你就要留意重复键覆盖问题。
真正顺手的数据处理,往往不是一步到位,而是:
先转换成更适合当前任务的容器 再进行下一步操作
把这一章吃透之后,你写代码时会明显更灵活。 因为你不再被某一种容器绑住,而是开始学会根据目标,主动调整数据的形状。
下一章我们继续讲 容器类型综合练习:做几个像样的小案例。 到那一章,前面这些列表、元组、字典、集合的知识点,就会真正串起来,开始像工具而不是知识点。