在程序设计中,经常会遇到要处理很多相同类型的数据的情况,比如统计全班同学的分数、统计每篇博客的浏览量、统计每种商品的单价等等。这时如果用一个变量存储一个数据,难免有些不便。Python中的序列类型就能很好地解决这些问题。
序列类型是组合数据类型的一类,能够将多个同类型或不同类型的数据组织起来,通过单一的表示使数据操作更有序更容易。
序列类型是一个元素向量,元素之间存在先后关系,通过序号访问,元素之间不排他。
Python中的主要序列类型:
- 字符串(
str
):由按照一定顺序组合在一起的字符来构成的,如:'Python'
- 列表(
list
):包含0个或多个不同类型元素的可变序列类型,用方括号将元素包含在一起,如:['Python', 1, 3.14, [2, 2.71], '555']
- 元组(
tuple
):包含0个或多个不同类型元素的不可变序列类型,用圆括号将元素包含在一起,如:('Python', 1, 3.14, (2, 2.71), '555')
所有序列类型都可以进行一些特定的操作,包括索引、切片、连接、重复、成员资格检查、计算元素出现次数等。
序列类型是一个元素向量,元素之间存在先后关系,所有元素都有序号(有时也称为偏移量或索引),序列中的元素可以通过序号进行访问,通过序号获取序列中特定位置的元素,就是索引:
l = ['Python', 1, 3.14, [2, 2.71], '555']
print(l[2])
除了可以从左往右地从0开始索引,也可以从右往左由-1开始索引,也可以混合使用:
l = ['Python', 1, 3.14, [2, 2.71], '555']
print(l[-2][1])
同时要注意,索引不能越界。
在使用序列类型数据的过程中,常常会遇到需要获取其中一部分数据的情况。这时,可以使用分片,它是索引的一种扩展方式,返回的是序列类型数据中的一个片段,而不是一个单独的元素。
切片的语法格式为:
<字符串>[<左边界>:<右边界>:<步长>]
对于切片,有以下一些需要注意的地方,以字符串
'Python'
为例:
- 包含左边界,不包含右边界。
- s[:] 获得包含所有字符的新字符串,缺省的左边界为 0,右边界为序列长度。
- s[0:2] 获得新字符串“Py”,即序号为 0 直到序号为 2 之前的所有字符。
- s[2:] 获得新字符串“thon”,即从序号 2 到最后的所有字符。
- s[:3] 获得新字符串“Pyt”,即从开头直到不包括序号为 3 之间的所有字符。
- s[:-1] 获得新字符串“Python”,即从开头直到不包括最后一个字符之间 的所有字符。
在切片时,除了可以指定左边界和右边界的序号外(或者不指定而使用缺省值),还可以增加第三个值,即步长。
步长用于规定切片的间隔:
s = '我是小嗷犬嗷嗷嗷'
print(s[1:6:2])
步长也可以是负数,即以相反的顺序来获取元素:
s = '我是小嗷犬嗷嗷嗷'
print(s[::-1])
+
操作符可以连接两个类型相同的序列,得到一个新的该类型序列,就像它将两个字符串合并成一个新字符串一样:
s = '我是小嗷犬' + '嗷嗷嗷'
print(s)
*
操作符也可以用于其他的序列类型,序列类型的值和一个整数n相乘,得到将该序列类型值重复n次的新的对象:
s = '我是小嗷犬' * 3
print(s)
通过运算符
in
可以判断某个元素是否在序列中,如果元素在序列中,in
表达式返回True,否则返回False。运算符not in
则正好相反:
email = '[email protected]'
print('@qq.com' in email)
当需要计算某个元素在序列中出现的次数时,使用序列的
count()
方法可以很轻松的完成这个任务:
fruits = ['apple', 'banana', 'apple', 'orange', 'apple', 'banana']
print(fruits.count('apple'))
序列类型有12个通用的操作符和函数:
操作符 | 描述 |
---|---|
x in s | 如果x是s的元素,返回True,否则返回False |
x not in s | 如果x不是s的元素,返回True,否则返回False |
s + t | 连接s和t |
s * n 或 n * s | 将序列s复制n次 |
s[i] | 索引,返回序列的第i个元素 |
s[i: j] | 切片,返回包含序列s第i到j个元素的子序列(不包含第j个元素) |
s[i: j: k] | 步骤切片,返回包含序列s第i到j个元素以j为步数的子序列 |
len(s) | 序列s的元素个数(长度) |
min(s) | 序列s中的最小元素 |
max(s) | 序列s中的最大元素 |
s.index(x[, i[, j]]) | 序列s中从i开始到j位置中第一次出现元素x的位置 |
s.count(x) | 序列s中出现x的总次数 |
列表是一个值,它包含多个值构成的序列。术语“列表值”指的是列表本身(它作为一个值,可以保存在变量中,或传递给函数,像所有其他值一样),而不是指列表值之内的那些值。
列表值看起来像这样:[‘apple’, ‘banana’, ‘orange’, ‘watermelon’]。
就像字符串值用引号来标记字符串的起止一样,列表用左方括号开始,右方括号结束,即[ ]。列表中的值也称为“表项”。表项用逗号分隔(就是说,它们是“逗号分隔的”)。
列表的长度和内容都是可变的,可自由对列表中数据项进行增加、删除或替换。列表没有长度限制,元素类型可以不同,使用非常灵活。
由于列表属于序列类型,所以列表也支持成员关系操作符(
in
)、长度计算函数(len()
)、切片([]
)。
列表可以同时使用正向递增序号和反向递减序号,可以采用标准的比较操作符(
<
、<=
、==
、!=
、>=
、>
)进行比较,列表的比较实际上是单个数据项的逐个比较。
列表的常用操作:
函数或方法 | 描述 |
---|---|
ls[i] = x | 替换列表ls第i数据项为x |
ls[i: j] = lt | 用列表lt替换列表ls中第i到j项数据(不含第j项,下同) |
ls[i: j: k] = lt | 用列表lt替换列表ls中第i到j以k为步的数据 |
del ls[i: j] | 删除列表ls第i到j项数据,等价于ls[i: j]=[] |
del ls[i: j: k] | 删除列表ls第i到j以k为步的数据 |
ls += lt或ls.extend(lt) | 将列表lt元素增加到列表ls中 |
ls *= n | 更新列表ls,其元素重复n次 |
ls.append(x) | 在列表ls最后增加一个元素x |
ls.clear() | 删除ls中所有元素 |
ls.copy() | 生成一个新列表,复制ls中所有元素 |
ls.insert(i, x) | 在列表ls第i位置增加元素x |
ls.pop(i) | 将列表ls中第i项元素取出并删除该元素 |
ls.remove(x) | 将列表中出现的第一个元素x删除 |
ls.reverse(x) | 列表ls中元素反转 |
ls.index(x) | 找出某个值第一个匹配项的索引位置 |
在Python中,通常用
list()
函数或方括号[]
来创建列表:
print(list('Python', 'Java', 'C'))
参数可以是字符串、元组、字典或者集合。但不能是整数、浮点数或者布尔值。
使用方括号
[]
创建列表时,需要在列表中列出所有元素:
print(['Python', 'Java', 'C'])
可以使用
list()
函数和方括号[]
创建空列表:
print(list())
print([])
列表也可以包含其他列表值。这些列表中的列表中的值,可以通过多重下标来访问,像这样:
ls = ['apple', 'banana', ['Python', 'Java', 'C']]
print(ls[2][-2])
由于列表是可变的, 因此列表有些专用的方法: 元素修改、元素删除和切片赋值。这些方法都是在列表原位置进行修改,也就是改变了列 表本身的值,而不是创建新的列表。
在列表创建后,可以通过元素赋值的方式修改列表中的元素。一般情况下,赋值语句左边是一个变量名,就像Pi = 3.14。但是,也可以使用列表的下标来改变下标处的值:
ls = ['apple', 'banana']
ls[1] = 'orange'
print(ls)
可以使用 Python 的内置函数 del 删除列表中的一个或多个元素:
ls = ['apple', 'banana', 'orange']
del ls[1]
print(ls)
Python 支持列表的分片赋值, 这使得仅仅用一步操作就可以将列表中的整个片段替换掉:
ls = ['apple', 'banana', 'orange']
ls[1:] = ['Python', 'Java']
print(ls)
当使用一个列表改变另一个列表值时,Python不要求两个列表长度一样,但遵循“多增少减”的原则。利用这个特性,可以通过分片赋值实现列表元素的删除和插入:
ls = ['apple', 'banana', 'orange']
ls[1:] = []
print(ls)
多重赋值是一种快捷方式,让你在一行代码中,用列表中的值为多个变量赋值:
ls = ['apple', 'banana', 'orange']
apple, banana, orange = ls
print(apple, banana, orange, sep='\n')
使用
extend()
方法, 可以一次在列表的末端插入多个元素。 这是一个对列表进行原地修改的方法。
ls1 = ['apple', 'banana', 'orange']
ls2 = ['Python', 'Java', 'C']
ls1.extend(ls2)
print(ls1)
也可以使用
+=
:
ls1 = ['apple', 'banana', 'orange']
ls2 = ['Python', 'Java', 'C']
ls1 += ls2
print(ls1)
append()
方法与extend()
类似,也可以在列表末端添加元素。 不同的是,使用append()
方 法会直接把传入的参数(可以是任何类型)添加到尾部而不是遍历它:
ls1 = ['apple', 'banana', 'orange']
ls2 = ['Python', 'Java', 'C']
ls1.append(ls2)
print(ls1)
使用
pop()
方法可以移除并返回指定列表中某个位置的元素。pop()
方法通过唯一的参数 指定需要移除并返回元素的位置,如果不指定,默认移除并返回最后一个元素:
ls = ['apple', 'banana', 'orange']
print(ls.pop(0))
print(ls)
copy()
方法会生成一个新的列表,复制调用者的所有元素:
ls = ['apple', 'banana', 'orange']
a = ls.copy()
print(ls)
print(a)
有的人可能会问,这么做有什么意义呢?为什么不直接将 ls 赋值给 a 呢?让我们先看一个实例:
ls = ['apple', 'banana', 'orange']
a = ls
ls.append('Python')
print(ls)
print(a)
a.append('Java')
print(ls)
print(a)
可以看出,这里的 ls 和 a 其实是同一个列表,这与 Python 自身的机制有关,当我们将一个列表赋值给另一个列表时其实并不是将列表中的内容赋值过去了,而是将原先列表的引用给赋值过去了,这就导致 ls 和 a 其实是同一个列表的两个不同的名字,使用
copy()
则能够使其分成两个独立的列表:
ls = ['apple', 'banana', 'orange']
a = ls.copy()
ls.append('Python')
print(ls)
print(a)
a.append('Java')
print(ls)
print(a)
数值的列表或字符串的列表,能用
sort()
方法排序。sort()
方法当场对列表排序:
ls = ['0001', '9876', '5432']
ls.sort()
# 默认升序排列
print(ls)
也可以指定reverse关键字参数为True,让
sort()
按逆序排序:
ls = ['0001', '9876', '5432']
ls.sort(reverse=True)
print(ls)
不能对既有数字又有字符串值的列表排序,因为 Python 不知道如何比较它们。
sort()
方法对字符串排序时,使用“ASCII 字符顺序”,而不是实际的字典顺序。这意味着大写字母排在小写字母之前。因此在排序时,小写的a 在大写的 Z 之后:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.sort()
print(ls)
sort()
方法有一个key的关键字参数,可以指定排序方法,例如:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.sort(key=len)
# 按长度排序
print(ls)
通过
insert()
方法可以将元素插入列表指定的位置,insert() 需要两个参数, 第 1 个参数指定需要插入的位置, 第 2 个参数指定需要插入的元素:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.insert(2, 'JavaScript')
print(ls)
通过
clear()
方法可以清空列表中的所有元素:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.clear()
print(ls)
通过
remove()
方法可以移除列表中的某个元素, 当元素在列表中重复出现时, 仅移除 第 1 次出现的值:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C']
ls.remove('C')
print(ls)
通过
reverse()
方法可以将列表中的元素反向存储:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.reverse()
print(ls)
通过
index()
方法找出列表某个值第一个匹配项的索引位置:
ls = ['Python', 'Java', 'C', 'Golang', 'C++', 'C#']
ls.index('C++')
print(ls)
除了两个方面,“元组”数据类型几乎与列表数据类型一样。
(1)用圆括号()表示
首先,元组输入时用圆括号
()
,而不是用方括号[]
:
tp = ('Python', 'Java', 'C')
print(tp)
(2)不可变性
元组与列表的主要区别还在于,元组像字符串一样,是不可变的。元组不能让它们的值被修改、添加或删除:
tp = ('Python', 'Java', 'C')
tp[1] = 'C++'
如果元组中只有一个值,你可以在括号内该值的后面跟上一个逗号,表明这种情况。否则,Python 将认为,你只是在一个普通括号内输入了一个值。逗号告诉 Python,这是一个元组(不像其他编程语言,Python 接受列表或元组中最后表项后面跟的逗号)。
a = ('Python')
print(type(a))
b = ('Python',)
print(type(b))
利用你可以用元组告诉所有读代码的人,你不打算改变这个序列的值。如果需要一个永远不会改变的值的序列,就使用元组。使用元组而不是列表的第二个好处在于,因为它们是不可变的,它们的内容不会变化,Python 可以实现一些优化,让使用元组的代码比使用列表的代码更快。
在 Python 中,创建列表通常用 tuple 函数或圆括号 ()。
与
list()
函数类似,tuple()
可以将参数中的可迭代对象转换成元组:
a = tuple('Python')
print(a)
b = tuple(['Python', 'Java', 'C'])
print(b)
使用圆括号
()
创建列表时,需要在列表中列出所有元素:
a = ('Python', 'Java', 'C')
print(a)
直接使用圆括号
()
将得到一个空的元组:
a = ()
print(a)
在 Python 中, 允许一次给多个变量赋值, 称为多重赋值。 可以使用元组和列表实现多重赋值:
a, b, c = ('Python', 'Java', 'C')
print(a, b, c, sep='\n')
在列表操作中, 除了对列表进行原地修改的方法, 其他方法都可以应用在元组中, 例如索引、分片、连接和重复等,与列表不同的是,在元组中使用这些方法,会返回新的元组,而不是列表。
如果仅仅使用圆括号把一个值括起来, Python 会认为是表达式, 得到的不会是元组类型,而是值本身的类型:
a = (3.14)
print(type(a))
所以,如果确实希望得到一个包含单个元素的元组,需要在这一单个元素后面加上一个逗号,与表达式区分开来:
a = (3.14,)
print(type(a))
在不引起歧义的情况下,可以省略圆括号:
a = 'Python', 'Java', 'C'
print(type(a))
不可变性也是元组和列表最大的区别。 如果试图修改元组的某个元素, 将会触发 TypeError 的异常:
a = ('Python', 'Java', 'C')
a[1] = 'C#'
元组的不可变性仅指的是不可以改变元组的顶层元素。如果元组中的元素本身是可变的,Python 允许修改其内容:
a = ('Python', ['Java', 'C'], 'Golang', 'C++')
a[1][1] = 'C#'
print(a)
主要原因如下:
- 元组占用的空间较小
- 你不会意外修改元组的值
- 可以将元组用作字典的键
- 函数的参数是以元组形式传递的