基本介绍
元组是值的序列。 这些值可以是任何类型,并且它们由整数进行索引,因此在这方面元组非常类似于列表。 重要的区别在于元组是不可变的(immutable)。
在语法上,tuple 是一个以逗号分隔的值列表,虽然没有必要,但常常将元组括在括号内。
t = 'a', 'b', 'c'
type(t)
#tuple
t = ('a', 'b', 'c')
type(t)
#tuple
要用创建一个 只有一个元素的元组,必须包含一个最后的逗号:
t = 'a',
type(t)
#tuple
括号中的只有一个元素不是元组:
t = ('a')
type(t)
#str
t = ('a',)
type(t)
#tuple
创造一个空的元组:
t =tuple()
t
#()
如果参数是一个序列(字符串、列表或元组) ,结果是一个包含所有其中元素的元组:
t =tuple('mathilda')
t
#('m', 'a', 't', 'h', 'i', 'l', 'd', 'a')
大多数列表操作符也用于元组:
t =tuple('mathilda')
t[0]
#'m'
t[1:3]
#('a', 't')
但是如果试图修改元组的一个元素,会报错:
t[0] = 'A'
#TypeError: 'tuple' object does not support item assignment
因为元组是不可变的,所以不能修改元素。 但是可以用另一个元组替换一个元组(注意第一个要是元组不能是‘M’),语句生成一个新元组,然后命名为t。
t = ('M',) + t[1:]
t
#('M', 'a', 't', 'h', 'i', 'l', 'd', 'a')
关系运算符处理元组和其他序列:Python 从比较每个序列的第一个元素开始。 如果它们相等,则继续到下一个元素,依此类推,直到找到不同的元素。 不考虑后续元素(即使它们非常大)。
(1, 2, 3) < (1, 1, 100)
#false
元组的交换赋值
一般我们要交换两个变量的值,我们会这么写:
temp = a
a = b
b = temp
元组的交换则会更为简略:
a, b = b, a
左边是一个变量元组,右边是一个表达式元组,每个值都分配给其各自的变量,右边的所有表达式都在任何赋值之前进行计算。左边和右边的元素个数必须相同。
右边可以是任何类型的序列(字符串、列表或元组)。 例如,将一个电子邮件地址分割成一个用户名和一个域名,可以这样写:
email = "yrc.mathilda@gmail.com"
uname, doname = email.split("@")
#uname:'yrc.mathilda' doname:gmail.com
返回元组
严格地说,一个函数只能返回一个值,但是如果该值是一个元组,那么可以返回多个值。 例如,如果希望除以两个整数并计算商和余数,那么计算x//y和x%y是低效的,可以同时计算它们。
内置函数divmod接受两个参数并返回两个值(商和余数)组成的元组。 可以将结果存储为一个元组,也可以用元组的赋值分别储存结果:
t = divmod(10, 4)
t
#(2, 2)
a, b = divmod(10, 4)
#a = 2, b = 2
这是一个函数返回元组的例子:
def first_last(l):
return l[0], l[-1]
first_last([1, 2, 3])
#(1, 3)
参数*
函数可以接受可变数量的参数。以为*开头的参数名称将参数收集到元组中。 比如说,
def first_last(*l):
print(type(l))
return l[0], l[-1]
first_last(1, 2, 3)
#<class 'tuple'>
#(1, 3)
*参数可以是任何名称,但是常规用args。
如果是一个元组,也可以用 * 来把它打散
t = (10, 4)
divmod(t)
#TypeError: divmod expected 2 arguments, got 1
divmod(*t)
#(2, 2)
许多内置函数比如max,min就是接受这种参数(Variable-length argument tuples)所以可以接收无数个参数
max(1, 2, 3, 4, 5, 6, 7, ...)
但是sum不可以
sum(1, 2, 3)
#TypeError: sum expected at most 2 arguments, got 3
参数**
*不能在像字典一样的对象中使用
def printall(*args):
print(args)
printall(1, 2, 3)
#(1, 2, 3)
printall(1, 2, third = 3)
#TypeError: printall() got an unexpected keyword argument 'third'
为了获得字典一样的参数可以用**来获取
def printall(*args, **kwargs):
print(args, kwargs)
printall(1, 2, 3)
#(1, 2, 3) {}
printall(1, 2, third = 3)
#(1, 2) {'third': 3}
题外话:a和d是等价的
d = dict(x=1, y=2)
a = {'x':1, 'y':2}
a == d
#True
更多的例子
print(1, 2, 3)
#等价于
print(*[1, 2, 3])
#为1 2 3, print([1, 2, 3])为[1, 2, 3]
def f(*args, **kwargs):
print("ARGS", args)
print("KWARGS", kwargs)
f(1, 2, x = 3, y = 4, z = 5)
#ARGS (1, 2)
#KWARGS {'x': 3, 'y': 4, 'z': 5}
list和tuple
zip是一个内置函数,它需要两个或多个序列,并将它们并在一起。
a = "abc"
b = (1, 2, 3)
zip(a, b)
#<zip at 0x7fe091401f08>
这样的结果是zip对象,但这个对象可以进行遍历,所以zip最常见的用途就是用在循环中
a = "abc"
b = (1, 2, 3)
for pair in zip(a, b):
print(pair)
#('a', 1)
#('b', 2)
#('c', 3)
zip对象是一种迭代器,在某些方面与列表相似,但与列表不同的是,不能使用索引从迭代器中选择元素。
如果想使用列表操作符和方法,可以这样:
list(zip(a, b))
#[('a', 1), ('b', 2), ('c', 3)]
type(list(zip(a, b))[0])
#tuple
结果是一个元组列表。
如果序列的长度不相同,则结果是选取较短序列的长度。
list(zip('avbc', 'sdf'))
#[('a', 's'), ('v', 'd'), ('b', 'f')]
还可以这样
a = "abc"
b = (1, 2, 3)
for ch, num in zip(a, b):
print(ch, num)
#a 1
#b 2
#c 3
如果需要遍历序列的元素及其索引,可以使用内置函数enumerate:
其结果是枚举对象,它迭代一系列对,每个对包含一个索引(从0开始)和一个来自给定序列的元素。
for index, ch in enumerate('abc'):
print(index, ch)
#0 a
#1 b
#2 c
字典和tuple
字典有一个名为items的方法,它返回一个元组序列,其中每个元组是一个键值对。items的对象可以用于循环,在字典里的元素没有特定顺序。
d = {'a':1, 'b':3, 'c':10}
d.items()
#dict_items([('a', 1), ('b', 3), ('c', 10)])
for key, val in d.items():
print(key, val)
#a 1
#b 3
#c 10
反过来,可以使用元组列表来初始化一个新的字典:
t = [('a', 1),('b', 3),('c', 10)]
dict(t)
#{'a': 1, 'b': 3, 'c': 10}
可以结合dict和zip非常简洁的创造字典:
dict(zip('abc', [1,2, 3]))
#{'a': 1, 'b': 2, 'c': 3}
字典中的update方法同样可以接收由tuple组成的list,并且添加到字典中。
在字典中使用tuple作为key是很普遍的,因为不能使用list
可以写:
d[a, b] = c
for a, b in d:
print(a, b, d[a, b])
这样在循环中的ab只会取值d的key赋值给ab