13 python 数据容器-元组
在 Python里,元组是一种很实用的数据类型,对于刚入门的学习者来说,它就像办公室里的文件收纳盒,能把相关的数据规整地放在一起。和列表有些相似,但元组有个很重要的特点 —— 一旦创建,里面的元素就不能修改啦
一、元组的定义
定义一个元组:
变量名 = (元素1,元素2,元素3,元素4,元素5,...)
定义一个空元组:
变量名 = ()
变量名 = tuple()
# 记录同事信息
colleague_info = ("小李", 1001, "研发部")
print(colleague_info)
# ('小李', 1001, '研发部')
创建空元组也很简单,直接写一对小括号就行:
empty_tuple = ()
print(empty_tuple)
# ()
如果元组里只有一个元素,一定要在元素后面加个逗号,不然 Python 会把它当成普通的变量。比如:
# 正确创建只有一个元素的元组
single_element_tuple = (5,)
# 错误示范,这样定义不是元组
wrong_single = (5)
print(single_element_tuple, type(single_element_tuple))
print(wrong_single, type(wrong_single))
# (5,) <class 'tuple'>
# 5 <class 'int'>
二、访问元组中的元素
元组里的每个元素都有自己的 “位置编号”,也就是索引。和字符串、列表一样,索引从 0 开始。通过索引,我们就能轻松访问元组里的元素。
比如,刚刚记录的同事信息 colleague_info
,想要获取姓名:
colleague_info = ("小李", 1001, "研发部")
name = colleague_info[0]
print(name)
# 小李
也可以从后往前索引,最后一个元素的索引是 -1 ,倒数第二个是 -2 ,以此类推。要是想获取部门信息:
colleague_info = ("小李", 1001, "研发部")
department = colleague_info[-1]
print(department)
还能对元组进行切片操作,获取一段连续的元素。比如有个元组记录了一周的工作任务:
tasks = ("周一:写报告", "周二:做数据整理", "周三:开会", "周四:测试产品", "周五:总结汇报")
# 获取周二到周四的任务
mid_week_tasks = tasks[1:4]
print(mid_week_tasks)
# ('周二:做数据整理', '周三:开会', '周四:测试产品')
三、合并和删除元组
前面提到,元组里的元素不能直接修改。比如,你不能把 colleague_info
里的工号直接改掉。不过,我们可以把两个元组连接起来,得到一个新的元组。就像把两个文件收纳盒合并成一个大的。例如:
info1 = ("小王", 1002, "市场部")
info2 = ("负责推广活动",)
new_info = info1 + info2
print(new_info)
# ('小王', 1002, '市场部', '负责推广活动')
如果想要删除元组,可以使用 del
语句。但要注意,这是删除整个元组,而不是删除里面的某个元素。比如,不再需要 info1
这个元组了:
删除之后,如果再尝试访问 info1
,就会报错,因为这个元组已经不存在啦。
info1 = ("小王", 1002, "市场部")
del info1
print(info1)
# NameError: name 'info1' is not defined
四、元组运算符
元组也有一些常用的运算符,能帮助我们处理数据。
- 计算元素个数:使用
len()
函数可以知道元组里有多少个元素。比如统计一个项目小组的人数:team_members = ("小张", "小赵", "小刘") member_count = len(team_members) print(member_count) # 3
- 连接元组:用
+
号可以把两个元组连接起来,生成一个新元组,前面已经举例说明过啦。 - 复制元组:
*
号可以用来复制元组。假如有个元组记录了每天必做的工作事项,要记录一周的:daily_task = ("查看邮件", "整理待办事项") weekly_task = daily_task * 3 print(weekly_task) # ('查看邮件', '整理待办事项', '查看邮件', '整理待办事项', '查看邮件', '整理待办事项')
- 检查元素是否存在:用
in
关键字可以检查某个元素是不是在元组里。比如检查某个同事是不是在项目小组里:team_members = ("小张", "小赵", "小刘") is_zhang_in_team = "小张" in team_members print(is_zhang_in_team) # True
- 迭代元组:可以通过
for
循环遍历元组里的每个元素。比如打印出项目小组每个成员的名字:team_members = ("小张", "小赵", "小刘") for member in team_members: print(member + " " , end = "") # 小张 小赵 小刘
五、元组内置函数
Python 为元组提供了几个实用的内置函数:
len(tuple)
:前面已经介绍过,用于计算元组元素的个数。max(tuple)
:返回元组中的最大元素。但要注意,元组里的元素类型得是可比较的,比如都是数字或者都是字符串。例如:number_tuple = (10, 20, 5, 30) max_number = max(number_tuple) print(max_number) # 30
min(tuple)
:返回元组中的最小元素。还是上面的例子:number_tuple = (10, 20, 5, 30) min_number = min(number_tuple) print(min_number) #
tuple(iterable)
:可以把其他可迭代的对象(比如列表)转换为元组。比如,有个列表记录了一些水果,想要转换成元组:fruit_list = ["苹果", "香蕉", "橙子"] fruit_tuple = tuple(fruit_list) print(fruit_tuple)
六、元组的不可变特性深入理解
元组的不可变是指它所指向的内存中的内容不能修改。举个例子,有个元组记录了办公室的一些设备信息:
devices = ("电脑", "打印机", "投影仪")
如果尝试修改其中某个元素,比如 devices[0] = "新电脑"
,就会报错。这是因为元组一旦创建,它里面元素的位置和值就固定了。
不过,当元组里包含可变对象(比如列表)时,情况会有点特殊。例如:
info = ("小李", [1001, "研发部"])
虽然不能直接修改元组里的列表,但是可以修改列表里面的内容。比如,小李换了工号:
info = ("小李", [1001, "研发部"])
info[1][0] = 1002
print(info)
# ('小李', [1002, '研发部'])
从表面上看,元组好像变了,但实际上变的是列表这个可变对象,而不是元组本身的元素指向。元组的每个元素指向是不变的,只是指向的列表对象内部发生了变化。
七、具名元组(namedtuple)
在办公室工作中,有时候我们使用元组,但很难从元组本身看出每个元素的含义。这时候,collections.namedtuple
就派上用场啦,它就像是给普通元组加上了标签,让每个元素都有自己的名字。
使用之前,需要先导入 collections
模块。比如,要记录员工的信息(姓名、年龄、职位):
import collections
# 定义具名元组
Employee = collections.namedtuple('Employee', ['name', 'age', 'position'])
# 创建具名元组实例
employee1 = Employee('小陈', 25, '程序员')
print(employee1)
# Employee(name='小陈', age=25, position='程序员')
具名元组有一些特殊的属性和方法:
_fields
:可以获取具名元组包含的所有字段名。比如:import collections # 定义具名元组 Employee = collections.namedtuple('Employee', ['name', 'age', 'position']) # 创建具名元组实例 employee1 = Employee('小陈', 25, '程序员') print(employee1._fields) # ('name', 'age', 'position')
_make(iterable)
:可以通过一个可迭代对象创建具名元组实例。例如:import collections # 定义具名元组 Employee = collections.namedtuple('Employee', ['name', 'age', 'position']) # 通过一个可迭代对象创建具名元组 data = ['小周', 28, '设计师'] employee2 = Employee._make(data) print(employee2) # Employee(name='小周', age=28, position='设计师')
可以思考一个问题,我改变了data列表中的值后,具名元组的值会变么?
_asdict()
:可以把具名元组转换为collections.OrderedDict
类型,方便展示元组里的信息。也就是转换成字典,字典后面会说,这里有一个概念就可以了。比如:import collections # 定义具名元组 Employee = collections.namedtuple('Employee', ['name', 'age', 'position']) # 通过一个可迭代对象创建具名元组 data = ['小周', 28, '设计师'] employee2 = Employee._make(data) employee_dict = employee2._asdict() print(employee2) print(employee_dict) # Employee(name='小周', age=28, position='设计师') # {'name': '小周', 'age': 28, 'position': '设计师'}
八、元组的装包与拆包
在办公室场景里,我们有时候会把一些物品放在一个大盒子里(打包),要用的时候再拿出来(拆包)。在 Python 里,元组也有类似的操作,而且是自动完成的。
- 装包:当把多个值赋给一个变量时,Python 会自动把这些值封装成一个元组。比如:
work_info = "写代码", 8, "完成功能模块开发" print(work_info) # ('写代码', 8, '完成功能模块开发')
- 拆包:把元组里的值分别赋给多个变量,就是拆包。比如:
task, hours, goal = ("做市场调研", 6, "收集竞品信息") print(task) print(hours) print(goal) # 做市场调研 # 6 # 收集竞品信息
理解元组的装包与拆包,对于处理函数返回值等情况很有帮助。比如,一个函数返回多个值,其实就是返回了一个装包后的元组。如果用多个变量接收,就会自动拆包。