Python 中的序列详解
Python 中的数字类型(Number)、字符串类型(String)之后,后续应该要继续讲元祖(Tuple)、列表(List)之类的。但是元祖和列表都属于序列,掌握序列(Sequence)的相关知识可以帮我们更容易的学习后续内容,所以有必要先了解一下 Python 中的序列是什么?
Python 中的序列
序列是一系列数据元素的有序集合,注意是有序的,它是 Python 中最基本的一种数据结构。
序列中的每个元素都被分配一个 数字 —- 它的位置,也就是我们说的元素的 索引。
第一个索引是 0,第二个索引是 1,依此类推……每个索引对应了一个 元素。
Python 包含 6 种内建的序列,包括 字符串(str)、元组(tuple)、列表(list)、Unicode 字符串、buffer 对象以及 range(xrange) 对象。
对于序列,都可以使用以下操作:
- 索引
- 切片
- 加(+)
- 乘(*)
- 成员检查
- 计算序列的长度
- 取序列中的最大、最小值
is && == && id()
在开始正式的解读之前,我们先来看几个必要的语法:
>>> id()
Python 中的 id() 内置函数,可用于获取对象的内存地址。语法规则如下:
1 | id(object) |
样例如下:
1 | >> str1 = "id() function test" |
>>> is && ==
Python 中经常会用到对象之间的比较,可以用 ==
,也可以用 is
。它们有什么区别?
- is:比较的是 两个实例对象是不是完全相同,是不是同一个对象(占用的内存地址是否相同);
- ==:比较的是 两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。
样例如下:
1 | >> str1 = "Python" |
序列中的索引
就像上面说的,序列中的每个元素都分配一个 数字 —- 它的位置,也就是我们说的元素的 索引。
[1] >>>> 两种索引方式:
正向索引:从前向后标记,第一个索引是 0,第二个索引是 1,依此类推。每个索引对应一个元素。
反向索引:序列中元素的索引也可以从后向前标记,最后一个索引是 -1,倒数第二个索引是 -2,以此类推。
[2] >>>> 可以通过索引获取序列中元素:
通过索引和 []
,我们可以获取到相应索引位置的元素对象:
1 | >> str_a = "Python" |
可以发现,字符串序列中通过索引取到的元素类型仍为字符串。
有个上面的知识储备,这里再重新认识一下序列是什么?!!
序列到底是什么?
所谓序列,
指的是一块可存放多个值的连续内存空间,这些值按一定顺序排列,可以是任何类型的对象元素,可通过值所在位置的编号(称为索引)获取相应的元素对象,并且取到的是元素原对象。
1 | >> list1 = [1] |
发现确实如此,也就是说,我们可以将序列中的索引看作是一个特殊的变量,它指向的是相应对象元素的内存空间,或着说,它对应了元素对象的引用。
字符串作为序列怎么解释?!! >>>>
不知道你发现没有:上面的说法套到字符串中略显变扭,因为字符串也是一个序列,难道字符串索引所对应的元素难道是一个个的字符(长度为一的字符串)对象???
我们先假设字符串是将每个字符(长度为一的字符串)都存储在一个个内存空间中(连续),字符串变量取得的是整个字符串,而索引则是每个字符的变量(引用)。来看一下假设结果如何:
1 | >> str_test = "abcdabcd" |
我们发现,哎,好像 感觉 假设成立啊?
那这样呢:
1 | >> str1 = "abcdabcd" |
看到这里你是不是明白了什么?!! >>>>
字符串是字符对象的引用的集合,所以我们使用英文的时候是不是最多只有创建 26 个字母,然后字符串只要重复引用就可以了。其他字符也同理。(是不有种常量缓存池的赶脚…)
关于常量缓存池请参见博文:Python 中的缓存重用机制(常量池)。
有了上面的理解,是不对序列的了解就更深一步了?
序列支持操作
博文开篇已经说明了序列支持 7 中操作:
序列中的索引和切片
索引不用多介绍了,所谓切片就是通过 [:] 配合序列索引一次拿出多个对象,而索引一次只能拿出一个对象。
1 | >> str1 = "abcdabcd" |
[1] >>>> 切片是前闭后开的:
上面返回的结果依然是一个字符串,这是要注意一个问题。还有就是 a[2]
明明是 c
才对,但结果我们并没有取到。
说明 >>>> 切片是不包括后界限的索引的,所以无法取到后界限索引所引用的元素(前闭后开)。
切片的其它用法 >>>>
1 | 获取所有所有元素对象: |
[2] >>>> 切片小技巧:
先看一个元组切片的样例:
1 | >> tup1 = ("Python", 123, [1,2]) |
我们知道,对序列切片,只是从包含多个元素对象的序列中取出包含部分元素对象的序列。如上面元组切片,切片后仍然得到的是一个元组,可以得到几个元素对象。
此时,我们可以使用多个变量去接收这些元素,这样我们能得到独立的对象进行其它操作了:
1 | >> tup1 = ("Python", 123, [1,2]) |
是不很方便?可以参见后面关于序列解包(Unpack)的说明。
[3] >>>> 切片中的步长概念:
所谓的切片步长,就是每几个元素对象取一个。如下:
1 | >> print(tup1[::2]) |
可以看到,对于 tup1 = ("Python", 123, [1,2])
我们每个 2 步长取一个元素的结果。
负向步长(即步长取值为负数) >>>> 可实现反序
1 | >> tup1 = ("Python", 123, [1,2]) |
加(+)
1 | >> tup1 = ("Python", 123, [1,2]) |
我们发现,同类型序列可以进行相加,并没有影响到原序列类型。
那么不同类型的序列相加呢? >>>> 不同类型序列不可直接相加!!!
1 | >> print(tup1 + str1) |
果然不行~~~
乘(*)
乘法和加法类似,只是几个一样的序列相加而已:
1 | >> tup1 = ("Python", 123, [1,2]) |
同样不会影响原序列。
成员检查(in && not in)
成员检查就是就是,判断元素对象是否(不)包含在序列中,返回的是布尔型值。如下:
1 | "Python", 123, [1,2]) tup1 = ( |
序列长度计算
其实就是 len()
内置函数的调用,该函数会返回序列容器中元素的数量。
1 | "Python", 123, [1,2]) tup1 = ( |
后面,你会发现:不仅仅是序列,集合(Set)和字典(Dict)也可以通过 len()
求元素个数。
取序列中的最大、最小值
这里其实是内置函数 max()
和 max()
的使用,其会返回序列中的最大、最小值。
关于不同序列最大、最小等到具体小节会介绍。
序列解包(Unpack)
序列中支持,通过序列解包的方式将序列中各元素对象分别赋给不同的变量,以获得单个元素的变量。
也就是说,可以直接使用序列元素个数对应数量的变量,来接收序列中的各个元素。
代码示例:
1 | str1 = "abc" |
新变量指向序列中各元素对象地址 >>>>
1 | list1 = ["Python", [1,2], {"good":2}] |
序列支持的内置函数
Python提供了几个内置函数,可用于实现与序列相关的一些常用操作:
函数 | 功能 |
---|---|
len() | 计算序列的长度,即返回序列中包含多少个元素。 |
max() | 找出序列中的最大元素。 |
min() | 找出序列中的最小元素。 |
list() | 将序列转换为列表。 |
str() | 将序列转换为字符串。 |
sum() | 计算元素和。注意,对序列使用 sum() 函数时,做加和操作的必须都是数字,不能是字符或字符串,否则该函数将抛出异常,因为解释器无法判定是要做连接操作(+ 运算符可以连接两个序列),还是做加和操作。 |
sorted() | 对元素进行排序。 |
reversed() | 反向序列中的元素。返回一个逆序序列的迭代器(用于遍历该逆序序列) |
enumerate() | 将序列组合为一个索引序列,多用在 for 循环中。 |
install_url
to use ShareThis. Please set it in _config.yml
.