数据类型介绍——tuple、list和range对象
本文作者:王 歌
文字编辑:宁刘莹
技术总编:张 邯
根据官网(https://docs.python.org/3/library/stdtypes.html)描述,Python解释器中主要的内置类型有数字、序列、映射、类、实例和异常(The following sections describe the standard types that are built into the interpreter. The principal built-in types are numerics, sequences, mappings, classes, instances and exceptions.),而对于我们存储信息时常用的内置类型——序列,Python也提供了多种类型,其中最基本的就是列表、元组和range对象(There are three basic sequence types: lists, tuples, and range objects.)。这三种类型相互之间存在很多相同点和不同点,今天的内容就让小编和大家一起由表及里,一探究竟。
1、列表(list)
(1)定义列表
列表使用方括号“[]”来创建,内部的元素用逗号“,”分隔,可以是任何数据类型,直接将所有元素列出即可定义一个列表:
In [1]: list_1=[1,'a',True] #可以包含数值型、字符型、布尔型等各种数据类型
In [2]: list_1
Out[2]: [1, 'a', True]
In [3]: list_2=[1,2,[1,'a',True]]
In [4]: list_2
Out[4]: [1, 2, [1, 'a', True]]
可以看到list_2中的第三个元素嵌套了列表list_1。
使用list()函数可以将字符串、元组等其它类型的数据转化为列表,若传入字典,则可以将字典的键转化为列表:
In [5]: list('abc') #传入字符串'abc'
Out[5]: ['a', 'b', 'c']
In [6]: list({'jack': 98, 'gudo': 27, 'rv': 41}) #传入字典{'jack': 98, 'gudo': 27, 'rv': 41}
Out[6]: ['jack', 'gudo', 'rv'] #得到由字典的键组成的列表
(2)对列表的操作
列表是可变的有序序列,因此可以对列表中的元素进行访问、增删、修改等操作。由于增删元素涉及到使用与列表有关的方法,且增删的基础都是使用列表元素的索引值,此处暂不涉及相关列表的方法,仅对访问、修改进行介绍。在Python中使用索引时,要注意索引值正序是从0开始计数,而逆序是从-1开始计数,以列表['爬','虫','俱','乐','部']为例:
如上图,第二行为正序时各元素对应的索引值,第三行为逆序时的索引值。由此我们可以对列表进行访问:
In [7]: list_3=['爬','虫','俱','乐','部']
In [8]: list_3[0] #访问list_3的第一个元素
Out[8]: '爬'
In [9]: list_3[-1] #访问list_3最后一个元素
Out[9]: '部'
若要访问多个元素,可以对列表进行切片——list[a:b],其中a为起始元素的索引,b为终止元素的索引,并且输出的元素中包含list[a]但不包含list[b],a、b都可以省略,此时a为0,b为列表长度len(list):
In [10]: list_3[:]
Out[10]: ['爬', '虫', '俱', '乐', '部']
In [11]: list_3[:len(list_3)]
Out[11]: ['爬', '虫', '俱', '乐', '部']
将第二个元素重新赋值为'hello'后,整个列表随之改变。
“+”可以将两个列表连接起来:
In [12]: list_2+list_3
Out[12]: [1, 2, [1, 'a', True], '爬', '虫', 'hello', '乐', '部']
执行操作后,list_3的元素连接在list_2后。
“*”可以将列表重复整数倍:
In [13]: list_3*2 #将list_3的元素重复两遍
Out[13]: ['爬', '虫', 'hello', '乐', '部', '爬', '虫', 'hello', '乐', '部']
在操作上,列表支持for循环的遍历:
In [14]: for i in list_3:
...: print(i)
输出结果为:
爬
虫
hello
乐
部
2、元组(tuple)
(1)定义元组
元组使用圆括号“()”与逗号“,”来创建,同样可以包含任意数据类型,其定义方法主要有以下几种:
In [15]: 1,'python',2.3
In [16]: tuple_1
Out[16]: (1, 'python', 2.3)
也可以由括号直接定义:
In [17]: tuple_2=(1,'python',2.3)
In [18]: tuple_2
Out[18]: (1,'python',2.3)
可以看到上面两种方式均可得到元组(1,'python',2.3)。
此处要注意,当元组中只有一个元素时,后面要带上逗号,否则得到的将不是元组:
In [19]: tuple_3=(1,)
In [20]: tuple_4=(1)
In [21]: print(type(tuple_3),type(tuple_4))
输出结果为:
<class 'tuple'> <class 'int'>
说明得到的tuple_3是元组,而tuple_4则是一个整型数字。
使用tuple()函数可以将字符串、列表等数据序列转化为元组,若传入字典,则同样可以将键转化为元组:
In [22]: tuple('abc') #传入字符串'abc'
Out[22]: ('a', 'b', 'c')
In [23]: tuple({'jack': 98, 'gudo': 27, 'rv': 41}) #传入字典{'jack': 98, 'gudo': 27, 'rv': 41}
Out[23]: ('jack', 'gudo', 'rv') #得到由字典的键组成的元组
(2)对元组的操作
不同于列表,元组是不可变有序序列,因此元组一旦被定义,就不能再增删修改,但仍然可以通过索引值进行访问。
In [24]: tuple_1[1]
Out[24]: 'python'
对上面定义的tuple_1=(1, 'python', 2.3),访问第二个元素,得到'python'。
也可以连接两个元组或将元组重复整数倍:
In [25]: tuple_1+tuple_3
Out[25]: (1, 'python', 2.3, 1)
In [26]: tuple_3*2
Out[26]: (1, 1)
此处与列表使用的符号相同,连接为“+”,重复为“*”。
当元组中的元素嵌套了可变的序列(如列表)时,此序列仍是可变的,但这并不意味着元组是可变的:
In [27]: tuple_5=(1,2,[1,2])
In [28]: tuple_5[2][1]=1 #将tuple_5中第三个元素[1,2]的第二个元素改为1
In [29]: tuple_5
Out[29]: (1, 2, [1, 1])
操作上,元组同样也支持for循环:
In [30]: for i in tuple_3:
...: print(i)
输出结果为:
1
3、range对象
range对象属于不可变的数字序列,其基本语法结构为:
range(start, stop[, step])
start和stop为起始值和中止值,step为步长,所有参数必须为整数,不可以为浮点数,可以只传入参数stop,此时默认起始值为0步长为1。其区间范围属于“左闭右开”,即起始值包括在内而终止值不在内。确定range对象中第r[i]项的值的公式为 r[i] = start + step*i 其中 i >= 0。下面通过一些例子来看看具体是如何使用的。
首先要注意,设定range()对象后若要查看其内容,不能使用print(),如:
In [31]: print(range(10))
此时输出如下:
range(0, 10)
可以看到输出结果并未明确显示range()中包含的内容,此时要达到显示的目的,应使用list()函数将range对象转化为列表:
In [32]: list(range(5, 10)) #起始值为5,终止值为9,步长为1
Out[32]: [5, 6, 7, 8, 9]
In [33]: list(range(-10, -100, -30)) #参数为负,起始值为-10,终止值为-70,步长为-30
Out[33]: [-10, -40, -70]
套用len()函数:
In [34]: a='abc'
In [35]: list(range(len(a))) #此时len(a)为终止值
Out[35]: [0, 1, 2]
此例中起始值为0,由于a的字符个数为3,因而终止值为2,步长为1,此时可以生成字符串索引值的序列。
当r[0] 不符合值的限制条件时并不会报错,生成的对象为空:
In [36]: list(range(1, 0)) #起始值为1终止值为0而步长为1,不符合限制条件
Out[36]: []
同样的,range对象支持for循环遍历:
In [37]: for value in range(1,3):
...: print(value)
输出结果为:
1
2
4、小结
从上面的介绍我们可以看出,元组和列表虽然都可以存储任意类型的序列,但是元组是不可变的,而列表是可变的,因此元组可以作为字典的键而列表不行,这也意味着两者在使用时内存占用和访问速度存在着差异。从存储方式上看,即便是存储相同的元素,元组的空间占用也会比列表要小:
In [38]:list_1=[1,2,3]
In [39]: list_1.__sizeof__() #显示分配的内存空间,单位为字节
Out[39]: 64
In [40]: tuple_1=(1,2,3)
In [41]: tuple_1.__sizeof__()
Out[41]: 48
同样为元素1、2、3,使用列表占用了64个字节,而元组只占用了48个字节。
运行速度上,通常情况下,如果一些变量不被使用了,Python 就会回收它们所占用的内存,返还给操作系统,以便其他变量或其他应用使用。但对于静态数据比如元组,Python 会在后台做一些资源缓存,如果它不被使用并且占用空间不大时,Python 会暂时缓存这部分内存。这样当再次创建元组时,Python 可以不用向操作系统发出请求寻找内存,而是直接分配之前缓存的内存空间,加快程序的运行速度。最后,虽然两者都可以存储任意类型数据,但在应用中,元组的数据强调异构,即元组内数据意义不同但有关联,比如一个人的各科成绩,使用元组来表示:(小明,语文,数学,英语);而列表偏重同构,即一些意义相同的数据,比如由多个人的成绩元组构成的列表:[(小明,语文,数学,英语), (小红,语文,数学,英语)].
而range 对象相比 list 或 tuple 的优势在于不论所表示的范围有多大,一个 range 对象总是占用较小的内存,因为它只保存了 start, stop 和 step 的值,并会根据需要计算具体单项或子范围的值,但表示同样的序列时,列表和元组就要将所有的数据传入,不论是否每个元素都需要。
最后,我们用一个表格来对今天的介绍进行总结和梳理:
因而三者都有各自存在的意义,我们在使用时要根据具体问题的需要灵活选择。
对爬虫俱乐部的推文累计打赏超过1000元我们即可给您开具发票,发票类别为“咨询费”。用心做事,只为做您更贴心的小爬虫!
往期推文推荐
字符串的小帮手之ascii()、str()和repr()函数
万般进制千机变,Python一计乾坤定——利用Python来进行进制转换
关于我们
微信公众号“爬虫俱乐部”分享实用的stata命令,欢迎转载、打赏。爬虫俱乐部是由李春涛教授领导下的研究生及本科生组成的大数据分析和数据挖掘团队。
此外,欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。
投稿邮箱:statatraining@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到关于stata分析数据的问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。