Python 元组

在上一部分,我们认识了 Python 中的列表(List),它就像一个可以随意增减和修改内容的购物清单。今天,我们要认识一位列表的近亲,但它的性格有点不一样,它就是元组(Tuple)

1. 什么是元组?

你可以把元组看作是一个只读的列表。它和列表非常相似,也是用来存储一系列有序的数据。但两者之间亦有区别

  • 相同点:都可以装很多不同类型的数据,比如数字、文字、甚至其他列表或元组,并且里面的元素都有自己的位置
  • 最大的不同点元组一旦创建,里面的元素就不能被修改、添加或删除了 。是不是感觉它比列表稳重多了?

2. 如何创建元组?

创建元组很容易,最常用的方法就是用小括号 () 把元素括起来,元素之间用逗号 , 隔开。

2.1 创建一个普通的元组

比如,我们想创建一个包含几种水果名称的元组:

1
2
fruits = ('apple', 'banana', 'cherry', 'date')
print(fruits) # 输出:('apple', 'banana', 'cherry', 'date')

再比如,一个包含数字和字符串的元组:

1
2
mixed_tuple = (10, "Hello", 3.14, True)
print(mixed_tuple) # 输出:(10, 'Hello', 3.14, True)

2.2 创建一个空元组

有时候,我们可能需要先创建一个空的元组,之后再往里添加内容。虽然不能修改元素,但可以通过一些特殊方法扩展,这个我们后面会提到。创建空元组就更简单了,直接用一对空的小括号:

1
2
3
empty_tuple = ()
print(empty_tuple) # 输出:()
print(type(empty_tuple)) # 输出:<class 'tuple'>,确认它是元组类型

2.3 只包含一个元素的元组 —— 别忘记逗号!

这是一个非常容易出错的地方。**当你想创建一个只包含一个元素的元组时,一定要在那个元素后面加上一个逗号 ,**。

为什么?因为如果不加逗号,Python 会把它当成一个普通的括号表达式,而不是元组

1
2
3
4
5
6
7
8
9
# 错误的方式:这不是一个元组!
not_a_tuple = (5)
print(not_a_tuple) # 输出:5
print(type(not_a_tuple)) # 输出:<class 'int'>,它只是一个整数

# 正确的方式:这才是一个元组!
single_element_tuple = (5,) # 注意元素后面的逗号
print(single_element_tuple) # 输出:(5,)
print(type(single_element_tuple)) # 输出:<class 'tuple'>,这才是元组类型

你看,就差一个小小的逗号,结果就完全不一样了,一定要谨记!!!

2.4 (了解)不用小括号也能创建元组

其实,在 Python 中,创建元组时,小括号有时候是可以省略的,只要元素之间用逗号隔开就行。

1
2
3
colors = "red", "green", "blue"  # 没有小括号
print(colors) # 输出:('red', 'green', 'blue')
print(type(colors)) # 输出:<class 'tuple'>

不过,为了代码的清晰易懂,尤其是对于初学者,建议还是加上小括号,这样一眼就能看出这是个元组。

3. 元组的基本操作预览

元组和字符串、列表一样,它们的元素都是有顺序的,下标(即,索引)也是从 0 开始。所以,我们可以像对待列表一样,对元组进行一些基本的操作,比如

  • 访问元组中的元素:通过索引值。
  • 截取元组的一部分:也就是切片操作。
  • 连接组合元组:把两个或多个元组拼成一个新元组。

这些具体怎么操作,将会在接下来的课程中详细介绍。


3. 如何访问元组中的元素?

我们已经创建了元组,那么怎么查看元组里面具体存了些什么,或者怎么把里面的某个元素取出来用?

别担心,元组的访问方式和我们之前学过的列表非常相似!因为元组和列表一样,元素都是有序排列的,所以我们可以通过它们的位置编号(其实就是索引) 来访问

3.1 通过索引访问单个元素

索引(Index)是什么?
你可以把元组想象成一个编号的储物柜,每个柜子(元素)都有一个唯一的门牌号(索引)。这个门牌号是从 0 开始计数的哦!第一个元素的索引是 0,第二个是 1,以此类推。(**这里再次说明了,这是一个很重要的概念,请一定要掌握!**)
语法:

1
元组名[索引值]

实例:

我们用之前创建的水果元组来举例:

1
fruits = ('apple', 'banana', 'cherry', 'date')

这个元组的索引和元素对应关系如下:

  • fruits[0] –> ‘apple’ (第一个元素,索引 0)
  • fruits[1] –> ‘banana’ (第二个元素,索引 1)
  • fruits[2] –> ‘cherry’ (第三个元素,索引 2)
  • fruits[3] –> ‘date’ (第四个元素,索引 3)

现在,我们来打开第二个柜子看看里面是什么:

1
2
fruits = ('apple', 'banana', 'cherry', 'date')
print(fruits[1]) # 我们想看看索引为 1 的元素是什么

运行结果:

1
banana

是不是很简单?我们成功取出了 ‘banana’!

再比如,访问 mixed_tuple 中的 “Hello”:

1
2
mixed_tuple = (10, "Hello", 3.14, True)
print(mixed_tuple[1]) # "Hello" 是第二个元素,索引为 1

运行结果:

1
Hello

3.2 通过切片访问多个连续元素

有时候,我们可能需要一次性获取元组中某一段连续的元素,而不是单个。这时候就可以用切片(Slicing) 操作。

语法:

1
元组名[开始索引 : 结束索引]
  • 开始索引:表示从哪个索引位置开始取(包含这个位置的元素)。
  • 结束索引:表示取到哪个索引位置结束 (不包含这个位置的元素!!!)
  • 如果省略开始索引,默认从 0 开始。
  • 如果省略结束索引,默认取到元组的最后一个元素。

实例:

我们还是用 fruits 元组:('apple', 'banana', 'cherry', 'date')

例 1:获取从索引 1 到索引 3(不包含 3)的元素

1
print(fruits[1:3])  # 从索引 1 开始,到索引 3 结束(但不包含索引 3 的元素)
  • 索引 1 是 ‘banana’ (包含)
  • 索引 2 是 ‘cherry’ (包含)
  • 索引 3 是 ‘date’ (不包含)
    运行结果:
    1
    ('banana', 'cherry')
    看,得到了一个新的元组 ('banana', 'cherry')

例 2:获取从索引 2 开始到最后的所有元素

1
print(fruits[2:])  # 从索引 2 开始,一直到最后

运行结果:

1
('cherry', 'date')

例 3:获取从开头到索引 2(不包含 2)的所有元素

1
print(fruits[:2])  # 从开头(索引 0)开始,到索引 2 结束(不包含索引 2)

运行结果:

1
('apple', 'banana')

再来看一个数字元组的例子:

1
2
3
numbers = (1, 2, 3, 4, 5, 6, 7)
# 我们想获取从索引 1 到索引 5(不包含 5)的元素
print(numbers[1:5])
  • 索引 1: 2 (包含)
  • 索引 2: 3 (包含)
  • 索引 3: 4 (包含)
  • 索引 4: 5 (包含)
  • 索引 5: 6 (不包含)
    运行结果:
    1
    (2, 3, 4, 5)
    这和我们上一页看到的示例结果是一样的

一些额外的提醒:
和列表一样,元组也支持负数索引,表示从元组的末尾开始计数。例如,fruits[-1] 表示最后一个元素 ‘date’。


4. 修改元组

我们在一开始就说过,元组是一个只读的列表。这是什么意思?

4.1 元组元素不可直接修改

简单来说,就是元组一旦创建完成,你就不能直接修改、添加或删除它里面的任何单个元素。

尝试修改元组元素会报错

比如,我们有一个元组 my_tuple

1
my_tuple = (10, 20, 30, 40)

如果我们想像列表那样,尝试把第一个元素改成 100:

1
my_tuple[0] = 100  # 尝试修改元组的第一个元素

运行这段代码,Python 会抛出一个错误:

1
TypeError: 'tuple' object does not support item assignment

翻译过来就是:类型错误:‘tuple’对象不支持元素赋值。

这就是元组的倔强。它坚守着自己不可变的原则。人也应当如此!

4.2 那么,我们就束手无策了吗?

虽然我们不能直接修改一个已有的元组,但我们可以通过连接或组合多个元组的方式,创建一个全新的元组。这就像是把几串不同的珠子串成一条新的项链

语法:

1
新元组 = 元组1 + 元组2 + ... + 元组N

实例:

假设我们有两个元组:

1
2
tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')

我们不能修改 tup1tup2,但是我们可以把它们加起来,得到一个包含所有元素的新元组 tup3

1
2
3
4
5
6
7
8
9
tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')

# 创建一个新的元组 tup3,它是 tup1 和 tup2 的组合
tup3 = tup1 + tup2

print("tup1:", tup1) # tup1 本身没有变
print("tup2:", tup2) # tup2 本身也没有变
print("tup3 (tup1 + tup2):", tup3) # 新的元组包含了 tup1 和 tup2 的所有元素

运行结果:

1
2
3
tup1: (12, 34.56)
tup2: ('abc', 'xyz')
tup3 (tup1 + tup2): (12, 34.56, 'abc', 'xyz')

看,我们成功地把 tup1tup2 的元素“合并”到了一个新的元组 tup3 里。原来的 tup1tup2 并没有被改变。

4.3 其他变通方式(了解即可)

除了连接组合,还有一些间接的方式可以达到类似修改元组的效果,比如:

  1. 将元组转换为列表,修改列表后再转换回元组:
    因为列表是可变的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    my_tuple = (10, 20, 30)
    print("原元组:", my_tuple)

    # 1. 将元组转换为列表
    temp_list = list(my_tuple)
    # 2. 修改列表
    temp_list[1] = 200 # 把第二个元素改成 200
    temp_list.append(40) # 添加一个新元素 40
    # 3. 将修改后的列表转换回元组
    my_tuple = tuple(temp_list)

    print("新元组:", my_tuple)

    运行结果:

    1
    2
    原元组: (10, 20, 30)
    新元组: (10, 200, 30, 40)

    注意:这并不是真的修改了原来的元组,而是创建了一个新的元组,并让原来的变量名指向了这个新元组。原来的旧元组如果没有其他变量引用,会被 Python 自动回收。

  2. 使用 * 运算符进行重复和组合(创建新元组):

    1
    2
    3
    tup = (1, 2)
    new_tup = tup * 3 # 将 tup 的元素重复 3 次,创建新元组
    print(new_tup) # 输出:(1, 2, 1, 2, 1, 2)

元组的这种不可变特性,使得它在某些场景下非常有用,比如存储一些不希望被意外修改的数据


5. 删除元组

既然元组的元素不能直接修改,那么元组的元素能直接删除吗?还有,整个元组能删除吗?

5.1 元组元素不可直接删除

和修改元素一样,你也不能直接删除元组中的某个单个元素。尝试这样做也会报错

例如:

1
2
fruits = ('apple', 'banana', 'cherry')
del fruits[0] # 尝试删除第一个元素

运行结果会报错:

1
TypeError: 'tuple' object doesn't support item deletion

意思是:类型错误:‘tuple’对象不支持元素删除。

5.2 使用 del 语句删除整个元组

虽然不能删除元组内的单个元素,但我们可以使用 del 语句来删除整个元组变量。这意味着这个元组变量将不再存在,我们也无法再访问它。

语法:

1
del 元组名

实例:

1
2
3
4
5
6
7
8
tup = ('physics', 'chemistry', 1997, 2000)
print("删除前的 tup:", tup) # 输出:删除前的 tup: ('physics', 'chemistry', 1997, 2000)

# 使用 del 语句删除整个元组
del tup

# 尝试打印已被删除的元组
print("删除后的 tup:", tup)

运行结果:

1
2
3
4
5
删除前的 tup: ('physics', 'chemistry', 1997, 2000)
Traceback (most recent call last):
File "test.py", line 7, in <module>
print("删除后的 tup:", tup)
NameError: name 'tup' is not defined

我们看到,在 del tup 之后,当我们再次尝试打印 tup 时,Python 会报错 NameError: name 'tup' is not defined,意思是名称错误:‘tup’这个名字没有被定义。这表明 tup 这个元组变量已经被成功删除了,它在内存中不复存在

简单来说:del tup 就像是把写有tup这个名字的标签从那个元组盒子上撕掉了,并且把盒子也扔掉了。从此以后,你就再也找不到这个叫tup的元组了


6. 元组运算符

元组支持一些非常实用的运算符,让我们可以像搭积木一样组合、复制元组,或者查询元素。这些运算符和我们在字符串上使用的非常类似

6.1 + 运算符

+ 号可以将两个或多个元组连接起来,形成一个全新的元组。原来的元组不会被改变

Python 表达式 结果 描述
(1, 2, 3) + (4, 5, 6) (1, 2, 3, 4, 5, 6) 连接两个元组

实例:

1
2
3
4
5
6
tup1 = (1, 2, 3)
tup2 = (4, 5, 6)
tup3 = tup1 + tup2
print(tup3) # 输出:(1, 2, 3, 4, 5, 6)
print(tup1) # 输出:(1, 2, 3) # tup1 本身没变
print(tup2) # 输出:(4, 5, 6) # tup2 本身也没变

6.2 * 运算符

* 号可以将元组中的元素重复指定的次数,形成一个全新的元组

Python 表达式 结果 描述
('Hi!',) * 4 ('Hi!', 'Hi!', 'Hi!', 'Hi!') 复制元组元素

实例:

1
2
3
greeting = ('Hi!',)  # 注意单个元素的元组,逗号不能少
repeated_greeting = greeting * 4
print(repeated_greeting) # 输出:('Hi!', 'Hi!', 'Hi!', 'Hi!')

6.3 len() 函数

len() 函数可以返回元组中元素的个数

Python 表达式 结果 描述
len((1, 2, 3)) 3 计算元素个数

实例:

1
2
fruits = ('apple', 'banana', 'cherry')
print(len(fruits)) # 输出:3,因为 fruits 有 3 个元素

6.4 in 运算符

in 运算符可以判断一个元素是否存在于元组中,如果存在返回 True,否则返回 False

Python 表达式 结果 描述
3 in (1, 2, 3) True 元素是否存在
4 in (1, 2, 3) False 元素是否不存在

实例:

1
2
3
numbers = (10, 20, 30, 40)
print(20 in numbers) # 输出:True,20 是元组中的元素
print(100 in numbers) # 输出:False,100 不是元组中的元素

6.5 for...in 循环

我们可以使用 for 循环来依次访问元组中的每个元素。

Python 表达式 结果(输出) 描述
for x in (1, 2, 3): print(x, end=' ') 1 2 3 迭代(遍历)元组

实例:

1
2
3
colors = ('red', 'green', 'blue')
for color in colors:
print(color)

运行结果:

1
2
3
red
green
blue

7. 元组索引与截取

我们之前已经简单介绍了如何通过索引访问单个元素和通过切片访问多个元素。因为元组也是一个序列,所以它的索引和切片操作和列表几乎完全一样。

我们用一个示例元组来详细看看:

1
L = ('spam', 'Spam', 'SPAM!')  # 一个包含三个字符串的元组

7.1 正向索引(从 0 开始)

Python 表达式 结果 描述
L[0] 'spam' 读取第一个元素(索引 0)
L[1] 'Spam' 读取第二个元素(索引 1)
L[2] 'SPAM!' 读取第三个元素(索引 2)

实例:

1
print(L[2])  # 输出:SPAM!  # 读取第三个元素

7.2 反向索引(从 -1 开始)

Python 表达式 结果 描述
L[-1] 'SPAM!' 读取倒数第一个元素(索引 -1)
L[-2] 'Spam' 读取倒数第二个元素(索引 -2)
L[-3] 'spam' 读取倒数第三个元素(索引 -3)

实例:

1
print(L[-2])  # 输出:Spam  # 反向读取,读取倒数第二个元素

7.3 切片(截取一段元素)

切片的语法是 元组名[开始索引:结束索引:步长],其中 步长 默认为 1,可以省略。注意,结束索引是开区间,不包含该索引本身的元素。

Python 表达式 结果 描述
L[1:] ('Spam', 'SPAM!') 从索引 1 开始,截取到最后(包含索引 1)
L[:2] ('spam', 'Spam') 从开头截取到索引 2(不包含索引 2)
L[0:2] ('spam', 'Spam') 从索引 0 截取到索引 2(不包含索引 2)
L[:] ('spam', 'Spam', 'SPAM!') 截取整个元组(创建一个副本)

实例:

1
print(L[1:])  # 输出:('Spam', 'SPAM!')  # 截取从索引 1 开始的所有元素

8. 无关闭分隔符

Python 有一种非常简洁的方式创建元组,即任意多个用逗号 , 分隔的、没有用括号括起来的对象,默认情况下会被认为是一个元组

8.1 直接用逗号分隔元素创建元组

实例:

1
2
# 打印几个用逗号分隔的值,Python 会将它们视为一个元组打印出来
print('abc', -4.24e93, 18+6.6j, 'xyz')

运行结果:

1
abc -4.24e+93 (18+6.6j) xyz

这里,'abc', -4.24e93, 18+6.6j, 'xyz' 这几个对象被逗号分隔,虽然没有用括号括起来,但它们实际上构成了一个元组。

8.2 变量赋值时的元组 unpacking(解包)

这在变量赋值时非常有用,可以同时给多个变量赋值:

实例:

1
2
3
# 将元组 (1, 2) 中的元素分别赋值给变量 x 和 y
x, y = 1, 2 # 等价于 (x, y) = (1, 2)
print("Value of x, y : ", x, y) # 输出:Value of x, y : 1 2

这里,1, 2 就是一个元组,我们把它的第一个元素赋给 x,第二个元素赋给 y。这种方式叫做元组解包。

注意, 当你想明确表示这是一个元组,或者在容易引起歧义的地方,比如函数参数,使用小括号 () 是一个好习惯,能让代码更清晰


9. 元组内置函数

Python 为元组提供了一些内置函数,帮助我们更方便地操作和查询元组。

9.1 cmp(tuple1, tuple2) - 比较两个元组 (Python 2.x)

点击查看:Python Tuple(元组) cmp()方法

描述
Python 元组 cmp() 函数用于比较两个元组的元素。

语法
cmp() 方法语法:

1
cmp(tuple1, tuple2)

参数

  • tuple1 – 要比较的第一个元组。
  • tuple2 – 要比较的第二个元组。

返回值

  • 如果 tuple1 小于 tuple2,则返回 -1
  • 如果 tuple1 大于 tuple2,则返回 1
  • 如果 tuple1 等于 tuple2,则返回 0

比较规则:

  1. 如果比较的元素是同类型的,则比较其值,返回上述结果。
  2. 如果两个元素不是同一种类型,则检查它们是否是数字。
    • 如果是数字,执行必要的数字强制类型转换,然后比较。
    • 如果有一方的元素是数字,则另一方的元素”大”(数字是”最小的”)。
    • 否则,通过类型名字的字母顺序进行比较。
  3. 如果有一个元组首先到达末尾,则另一个长一点的元组”大”。
  4. 如果两个元组的所有元素都相等且长度相同,则返回 0。

实例
以下实例展示了 cmp() 函数的使用方法(注意:此代码在 Python 3.x 中会报错):

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/python

tuple1, tuple2 = (123, 'xyz'), (456, 'abc')

print(cmp(tuple1, tuple2)) # tuple1 < tuple2,输出 -1
print(cmp(tuple2, tuple1)) # tuple2 > tuple1,输出 1
tuple3 = tuple2 + (786,) # tuple3 比 tuple2 长
print(cmp(tuple2, tuple3)) # tuple2 < tuple3,输出 -1
tuple4 = (123, 'xyz') # tuple4 与 tuple1 完全相同
print(cmp(tuple1, tuple4)) # tuple1 == tuple4,输出 0

以上实例在 Python 2.x 中的输出结果如下:

1
2
3
4
-1
1
-1
0

一篇笔记:
Python 3.X 的版本中已经移除了 cmp() 函数。如果你需要实现比较功能,可以使用:

  • 直接使用比较运算符:==, !=, <, <=, >, >=

  • 引入 operator 模块,该模块提供了与比较运算符对应的函数,适合任何对象。包含的方法有:

    函数 描述 等价于
    operator.lt(a, b) a 小于 b 时返回 True a < b
    operator.le(a, b) a 小于等于 b 时返回 True a <= b
    operator.eq(a, b) a 等于 b 时返回 True a == b
    operator.ne(a, b) a 不等于 b 时返回 True a != b
    operator.ge(a, b) a 大于等于 b 时返回 True a >= b
    operator.gt(a, b) a 大于 b 时返回 True a > b
    operator.__lt__(a, b) 同上,用于类的运算符重载 a < b
    operator.__le__(a, b) 同上,用于类的运算符重载 a <= b
    operator.__eq__(a, b) 同上,用于类的运算符重载 a == b
    operator.__ne__(a, b) 同上,用于类的运算符重载 a != b
    operator.__ge__(a, b) 同上,用于类的运算符重载 a >= b
    operator.__gt__(a, b) 同上,用于类的运算符重载 a > b

实例(Python 3.x 使用 operator 模块):

1
2
3
4
5
6
7
8
9
>>> import operator
>>> operator.eq('hello', 'name') # 'hello' == 'name'?
False
>>> operator.eq('hello', 'hello') # 'hello' == 'hello'?
True
>>> operator.lt((1,2), (1,3)) # (1,2) < (1,3)?
True
>>> operator.gt((2,), (1,2)) # (2,) > (1,2)?
True

9.2 len(tuple) - 计算元组元素个数

点击查看:Python Tuple(元组) len()方法

描述
Python 元组 len() 函数用于计算元组中元素的个数,即返回元组的长度。

语法
len() 方法语法:

1
len(tuple)

参数

  • tuple – 要计算元素个数的元组。

返回值

  • 一个整数,表示元组中元素的数量。

实例
以下实例展示了 len() 函数的使用方法:

1
2
3
4
5
6
7
8
fruits = ('apple', 'banana', 'cherry', 'date')
print(len(fruits)) # 计算 fruits 元组有多少个元素

empty_tuple = ()
print(len(empty_tuple)) # 计算空元组的长度

single_tuple = (5,)
print(len(single_tuple)) # 计算只有一个元素的元组的长度

运行结果:

1
2
3
4
0
1

9.3 max(tuple) - 返回元组中元素的最大值

点击查看:Python Tuple(元组) max()方法

描述
Python 元组 max() 函数用于返回元组中所有元素的最大值

语法
max() 方法语法:

1
max(tuple)

参数

  • tuple – 要从中找出最大值的元组。

返回值

  • 返回元组中元素的最大值。

实例
以下实例展示了 max() 函数的使用方法:

1
2
3
4
5
6
7
8
9
10
11
# 数字元组
numbers = (10, 20, 5, 35, 15)
print("数字元组中的最大值:", max(numbers)) # 输出:35

# 字符串元组 (比较的是字符的 Unicode 编码值)
fruits = ('apple', 'banana', 'cherry', 'date')
print("字符串元组中的最大值:", max(fruits)) # 输出:'date' (因为 'd' 的 Unicode 值大于 'a', 'b', 'c')

# 混合类型元组 - 注意:不同类型的元素之间不能比较,会报错!
# mixed = (10, 'apple', 3.14)
# print(max(mixed)) # 会抛出 TypeError: '>' not supported between instances of 'str' and 'int'

运行结果:

1
2
数字元组中的最大值: 35
字符串元组中的最大值: date

注意事项:

  1. max() 函数要求元组中的元素之间必须是可比较的。如果元组中包含不可比较类型的元素(如同时包含数字和字符串),则会抛出 TypeError
  2. 对于字符串元组,比较的是字符串中字符的 Unicode 编码值,通常是按照字母顺序进行比较的。
  3. 对于空元组,调用 max() 会抛出 ValueError: max() arg is an empty sequence

9.4 min(tuple) - 返回元组中元素的最小值

点击查看:Python Tuple(元组) min()方法

描述
Python 元组 min() 函数用于返回元组中所有元素的最小值

语法
min() 方法语法:

1
min(tuple)

参数

  • tuple – 要从中找出最小值的元组。

返回值

  • 返回元组中元素的最小值。

实例
以下实例展示了 min() 函数的使用方法:

1
2
3
4
5
6
7
8
9
10
11
# 数字元组
numbers = (10, 20, 5, 35, 15)
print("数字元组中的最小值:", min(numbers)) # 输出:5

# 字符串元组 (比较的是字符的 Unicode 编码值)
fruits = ('apple', 'banana', 'cherry', 'date')
print("字符串元组中的最小值:", min(fruits)) # 输出:'apple' (因为 'a' 的 Unicode 值小于 'b', 'c', 'd')

# 混合类型元组 - 注意:不同类型的元素之间不能比较,会报错!
# mixed = (10, 'apple', 3.14)
# print(min(mixed)) # 会抛出 TypeError: '<' not supported between instances of 'str' and 'int'

运行结果:

1
2
数字元组中的最小值: 5
字符串元组中的最小值: apple

注意事项:

  1. min() 函数要求元组中的元素之间必须是可比较的。如果元组中包含不可比较类型的元素(如同时包含数字和字符串),则会抛出 TypeError
  2. 对于字符串元组,比较的是字符串中字符的 Unicode 编码值,通常是按照字母顺序进行比较的。
  3. 对于空元组,调用 min() 会抛出 ValueError: min() arg is an empty sequence

9.5 tuple(seq) - 将序列转换为元组

点击查看:Python tuple() 函数 (用于创建元组或转换序列为元组)

描述
Python tuple() 函数用于将一个可迭代序列(如列表、字符串、字典等)转换为一个元组。如果不提供参数,它将创建一个空元组。

语法
tuple() 函数语法:

1
tuple(seq)

参数

  • seq (可选) – 要转换为元组的可迭代序列(如列表、字符串、集合、字典等)。如果省略此参数,则创建一个空元组。

返回值

  • 一个新的元组,包含了序列 seq 中的所有元素(如果提供了 seq);否则返回一个空元组。

实例
以下实例展示了 tuple() 函数的使用方法:

实例 1:将列表转换为元组

1
2
3
4
my_list = [1, 2, 3, 4, 5]
my_tuple = tuple(my_list)
print("转换后的元组:", my_tuple) # 输出:转换后的元组: (1, 2, 3, 4, 5)
print("原列表:", my_list) # 输出:原列表: [1, 2, 3, 4, 5] (原列表不变)

实例 2:将字符串转换为元组(每个字符成为元组的一个元素)

1
2
3
my_str = "hello"
str_tuple = tuple(my_str)
print("字符串转换后的元组:", str_tuple) # 输出:字符串转换后的元组: ('h', 'e', 'l', 'l', 'o')

实例 3:创建空元组

1
2
empty_tuple = tuple()
print("空元组:", empty_tuple) # 输出:空元组: ()

实例 4:将字典转换为元组(默认取字典的键)

1
2
3
4
5
6
my_dict = {'name': 'Alice', 'age': 30}
dict_tuple = tuple(my_dict)
print("字典键转换后的元组:", dict_tuple) # 输出:字典键转换后的元组: ('name', 'age')
# 如果想转换字典的值或键值对,可以使用 .values() 或 .items()
dict_values_tuple = tuple(my_dict.values())
print("字典值转换后的元组:", dict_values_tuple) # 输出:字典值转换后的元组: ('Alice', 30)

一篇笔记:
tuple() 函数不是直接改变原序列的类型,而是返回一个新的、转换类型后的元组原序列不会被修改或改变类型。这意味着:

  • 如果原序列是可变的(如列表),你仍然可以修改原列表,但这不会影响通过 tuple() 函数创建的新元组。
  • 转换后的元组本身是不可变的,不能修改其元素。

示例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
test_list1 = ('a', 'b', 'c')  # 这本身就是一个元组
test_list2 = ['x', 'y', 'z'] # 这是一个列表

# 将列表 test_list2 转换为元组
test_tuple = tuple(test_list2)

# test_list2 是列表,可以修改
test_list2[2] = '这是修改的'

# 下面这行代码会报错,因为 test_list1 是元组,元组不可修改
# test_list1[2] = '这是修改的'

print("test_list1 (原元组):", test_list1) # 输出:test_list1 (原元组): ('a', 'b', 'c')
print("test_list2 (修改后的原列表):", test_list2) # 输出:test_list2 (修改后的原列表): ['x', 'y', '这是修改的']
print("test_tuple (由原列表转换的元组):", test_tuple) # 输出:test_tuple (由原列表转换的元组): ('x', 'y', 'z')

运行结果:

1
2
3
test_list1 (原元组): ('a', 'b', 'c')
test_list2 (修改后的原列表): ['x', 'y', '这是修改的']
test_tuple (由原列表转换的元组): ('x', 'y', 'z')

从上面的例子可以看出:

  • test_list2 被修改后,其内容发生了变化。
  • 而通过 tuple(test_list2) 创建的 test_tuple 仍然保持了转换时 test_list2 的状态,不受后续 test_list2 修改的影响。
  • test_list1 作为元组,尝试修改其元素会直接报错。

至此,我们已经介绍了 Python 元组常用的内置函数:cmp() (Python 2.x)、len()max()min()tuple()。这些函数能帮助我们有效地操作和处理元组数据


Python 元组练习题

练习 1:创建与访问

题目:

  1. 创建一个名为 my_tuple 的元组,包含元素 “apple”, 100, 3.14, True。
  2. 打印 my_tuple 的长度。
  3. 访问并打印 my_tuple 中的第二个元素(索引为 1)。
  4. 访问并打印 my_tuple 中的最后一个元素(使用负数索引)。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
# 1. 创建元组
my_tuple = ("apple", 100, 3.14, True)

# 2. 打印元组长度
print("元组长度:", len(my_tuple)) # 输出:元组长度: 4

# 3. 访问第二个元素 (索引 1)
print("第二个元素:", my_tuple[1]) # 输出:第二个元素: 100

# 4. 访问最后一个元素 (负数索引 -1)
print("最后一个元素:", my_tuple[-1]) # 输出:最后一个元素: True

练习 2:元组切片

题目:
给定元组 numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10),使用切片完成以下操作:

  1. 获取包含元素 3,4,5 的子元组。
  2. 获取包含元素 7,8,9,10 的子元组。
  3. 获取包含元素 1,3,5,7,9 的子元组(步长为 2)。
  4. 获取元组 numbers 的逆序元组(从后往前)。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

# 1. 获取包含元素 3,4,5 的子元组 (索引 2,3,4)
sub1 = numbers[2:5] # 从索引2开始,到索引5(不包含)结束
print("子元组 3,4,5:", sub1) # 输出:子元组 3,4,5: (3, 4, 5)

# 2. 获取包含元素 7,8,9,10 的子元组 (索引 6,7,8,9)
sub2 = numbers[6:] # 从索引6开始到结束
print("子元组 7,8,9,10:", sub2) # 输出:子元组 7,8,9,10: (7, 8, 9, 10)

# 3. 获取包含元素 1,3,5,7,9 的子元组(步长为 2)
sub3 = numbers[::2] # 从头到尾,步长2
print("子元组 1,3,5,7,9:", sub3) # 输出:子元组 1,3,5,7,9: (1, 3, 5, 7, 9)

# 4. 获取元组的逆序元组
reversed_numbers = numbers[::-1] # 从头到尾,步长-1(反向)
print("逆序元组:", reversed_numbers) # 输出:逆序元组: (10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

练习 3:元组运算符

题目:

  1. 创建元组 t1 = (1, 2, 3)t2 = ('a', 'b')
  2. 使用 + 运算符将 t1t2 连接起来,创建一个新的元组 t3 并打印。
  3. 使用 * 运算符将 t2 复制 3 次,创建一个新的元组 t4 并打印。
  4. 检查元素 'a' 是否在 t3 中,并打印结果。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 创建元组
t1 = (1, 2, 3)
t2 = ('a', 'b')

# 2. 连接 t1 和 t2
t3 = t1 + t2
print("t1 + t2 =", t3) # 输出:t1 + t2 = (1, 2, 3, 'a', 'b')

# 3. 复制 t2 3 次
t4 = t2 * 3
print("t2 * 3 =", t4) # 输出:t2 * 3 = ('a', 'b', 'a', 'b', 'a', 'b')

# 4. 检查 'a' 是否在 t3 中
is_present = 'a' in t3
print("'a' 在 t3 中吗?", is_present) # 输出:'a' 在 t3 中吗? True

练习 4:元组内置函数

题目:

  1. 创建一个包含数字的元组 scores = (85, 92, 78, 90, 88, 76)
  2. 使用 len() 函数计算该元组的长度并打印。
  3. 使用 max() 函数找出最高分并打印。
  4. 使用 min() 函数找出最低分并打印。
  5. 尝试将列表 ['Python', 'Java', 'C++'] 转换为元组 lang_tuple 并打印。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 创建分数元组
scores = (85, 92, 78, 90, 88, 76)

# 2. 计算长度
print("学生人数:", len(scores)) # 输出:学生人数: 6

# 3. 找出最高分
print("最高分:", max(scores)) # 输出:最高分: 92

# 4. 找出最低分
print("最低分:", min(scores)) # 输出:最低分: 76

# 5. 将列表转换为元组
lang_list = ['Python', 'Java', 'C++']
lang_tuple = tuple(lang_list)
print("转换后的语言元组:", lang_tuple) # 输出:转换后的语言元组: ('Python', 'Java', 'C++')

练习 5:综合应用(元组与列表)

题目:
小明记录了一周的气温(摄氏度),数据如下:[22, 24, 25, 23, 26, 28, 27]

  1. 将这个列表转换为一个名为 temperatures 的元组。
  2. 尝试修改元组中的第一个元素(比如改为 20),观察会发生什么错误,并记录错误信息。
  3. 创建一个新的列表 new_temps,将元组 temperatures 中的所有元素加 2 度(模拟温度普遍升高)。
  4. new_temps 列表转换为一个新的元组 new_temperatures
  5. 分别打印原始温度元组和新的温度元组。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 将列表转换为元组
temp_list = [22, 24, 25, 23, 26, 28, 27]
temperatures = tuple(temp_list)
print("原始温度元组:", temperatures)

# 2. 尝试修改元组中的第一个元素 (会报错)
try:
temperatures[0] = 20
except TypeError as e:
print("尝试修改元组元素时发生错误:", e) # 输出:尝试修改元组元素时发生错误: 'tuple' object does not support item assignment

# 3. 创建新列表,所有温度加 2 度
new_temps = []
for temp in temperatures:
new_temps.append(temp + 2)
# 或者使用列表推导式:new_temps = [temp + 2 for temp in temperatures]

# 4. 将新列表转换为新元组
new_temperatures = tuple(new_temps)

# 5. 打印结果
print("原始温度元组:", temperatures)
print("新的温度元组 (各加 2 度):", new_temperatures)

运行结果:

1
2
3
4
原始温度元组: (22, 24, 25, 23, 26, 28, 27)
尝试修改元组元素时发生错误: 'tuple' object does not support item assignment
原始温度元组: (22, 24, 25, 23, 26, 28, 27)
新的温度元组 (各加 2 度): (24, 26, 27, 25, 28, 30, 29)

练习 6:元组的不可变性与保护数据

题目:
假设你正在编写一个程序,需要存储一些配置信息,这些信息在程序运行期间不应该被修改(例如:数据库服务器地址、端口号、默认编码)。

  1. 使用一个元组来存储这些配置信息:服务器地址 '192.168.1.100',端口号 3306,默认编码 'utf-8'
  2. 编写代码尝试修改端口号为 8080,观察结果。
  3. 打印出配置信息中的服务器地址。
点击查看参考答案
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 使用元组存储配置信息
config = ('192.168.1.100', 3306, 'utf-8') # (服务器地址, 端口号, 默认编码)
print("初始配置信息:", config)

# 2. 尝试修改端口号 (会报错,体现元组的不可变性,保护配置不被意外修改)
try:
config[1] = 8080
except TypeError as e:
print("尝试修改配置时发生错误:", e) # 输出:尝试修改配置时发生错误: 'tuple' object does not support item assignment

# 3. 打印服务器地址
server_address = config[0]
print("服务器地址:", server_address) # 输出:服务器地址: 192.168.1.100

运行结果:

1
2
3
初始配置信息: ('192.168.1.100', 3306, 'utf-8')
尝试修改配置时发生错误: 'tuple' object does not support item assignment
服务器地址: 192.168.1.100

希望这些练习能帮助你更好地理解和掌握 Python 元组的特性和用法!如果遇到困难,随时回顾前面的知识点或者查看参考答案。编程是熟能生巧的过程,多动手练习吧!