关于python:Python从入门到精通六Python内置的数据类型列表list和元组tuple九浅一深用得到

6次阅读

共计 10178 个字符,预计需要花费 26 分钟才能阅读完成。

您好,我是码农飞哥,感谢您浏览本文,欢送一键三连哦
本文分十个章节介绍数据类型中的列表(list)和元组(tuple),从应用说到底层实现,包您称心
干货满满,倡议珍藏,须要用到时常看看。小伙伴们如有问题及须要,欢送踊跃留言哦~ ~ ~。

@[TOC]

一浅: 列表(list)的介绍

列表作为 Python 序列类型中的一种,其也是用于存储多个元素的一块内存空间,这些元素依照肯定的顺序排列。其数据结构是:

[element1, element2, element3, ..., elementn]

element1~elementn 示意列表中的元素,元素的数据格式没有限度,只有是 Python 反对的数据格式都能够往里面方。同时因为列表反对主动扩容,所以它可变序列,即能够动静的批改列表,即能够批改,新增,删除列表元素。看个爽图吧!

二浅:列表的操作

首先介绍的是对列表的操作:包含列表的创立,列表的删除等!其中创立一个列表的形式有两种:
第一种形式:
通过 [] 包裹列表中的元素,每个元素之间通过逗号 , 宰割。元素类型不限并且同一列表中的每个元素的类型能够不雷同,然而不倡议这样做,因为如果每个元素的数据类型都不同的话则十分不不便对列表进行遍历解析。所以倡议一个列表只存同一种类型的元素

   list=[element1, element2, element3, ..., elementn]

例如:test_list = ['测试', 2, ['码农飞哥', '小伟'], (12, 23)]
PS: 空列表的定义是 list=[]
第二种形式:
通过 list(iterable) 函数来创立列表,list 函数是 Python 内置的函数。该函数传入的参数必须是 可迭代的序列 ,比方字符串,列表,元组等等,如果iterable 传入为空,则会创立一个空的列表。iterable不能只传一个数字。

classmates1 = list('码农飞哥')
print(classmates1)

生成的列表是:['码', '农', '飞', '哥']

三浅:向列表中新增元素

向列表中新增元素的办法有四种,别离是:
第一种: 应用 + 运算符将 多个列表 连接起来。相当于在第一个列表的开端增加上另一个列表。其语法格局是listname1+listname2

name_list = ['码农飞哥', '小伟', '小小伟']
name_list2 = ['python', 'java']
print(name_list + name_list2)

输入后果是:['码农飞哥', '小伟', '小小伟', 'python', 'java'],能够看出将 name_list2 中的每个元素都增加到了 name_list 的开端。
第二种:应用 append()办法增加元素
append() 办法用于向列表开端增加元素,其语法格局是:listname.append(p_object)其中 listname 示意要增加元素的列表,p_object 示意要增加到列表开端的元素,能够是字符串,数字,也能够是一个序列。举个栗子:

name_list.append('Adam')
print(name_list)
name_list.append(['test', 'test1'])
print(name_list)

运行后果是:

['码农飞哥', '小伟', '小小伟', 'Adam']
['码农飞哥', '小伟', '小小伟', 'Adam', ['test', 'test1']]

能够看出待增加的元素都胜利的增加到了原列表的开端处。并且当增加的元素是一个序列时,则会将该序列当成一个整体。
第三种:应用 extend()办法
extend() 办法跟 append()办法的用法雷同,同样是向列表开端增加元素。元素的类型只须要 Python 反对的数据类型即可。不过与 append()办法不同的是,当增加的元素是序列时,extend()办法不会将列表当成一个整体,而是将每个元素增加到列表开端。还是下面的那个例子:

name_list = ['码农飞哥', '小伟', '小小伟']
name_list.extend('Adam')
print(name_list)
name_list.extend(['test', 'test1'])
print(name_list)

运行后果是:

['码农飞哥', '小伟', '小小伟', 'A', 'd', 'a', 'm']
['码农飞哥', '小伟', '小小伟', 'A', 'd', 'a', 'm', 'test', 'test1']

从后果看出,当增加字符串时会将字符串中的每个字符作为一个元素增加到列表的开端处,当增加的列表时会将列表中的每个元素增加到开端处。
第四种:应用 insert()办法
后面介绍的几种插入方法,都只能向列表的开端处插入元素,如果想在列表指定地位插入元素则无能为力。insert()办法正式用于解决这种问题而来的。其语法结构是 listname.insert(index, p_object) 其中 index 示意指定地位的索引值,insert() 会将 p_object 插入到 listname 列表第 index 个元素的地位。与 append()办法雷同的是,如果待增加的元素的是序列,则 insert()会将该序列当成一个整体插入到列表的指定地位处。举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟']
name_list.insert(1, 'Jack')
print(name_list)
name_list.insert(2, ['test', 'test1'])
print(name_list)

运行后果是:

['码农飞哥', 'Jack', '小伟', '小小伟']
['码农飞哥', 'Jack', ['test', 'test1'], '小伟', '小小伟']

四浅:批改列表中的元素

说完了列表中元素新增的办法,接着让咱们来看看批改列表中的元素相干的办法。批改列表元素的办法有两种:
第一种:批改单个元素:
批改单个元素的办法就是对某个索引上的元素进行从新赋值。其语法结构是:listname[index]=newValue,就是将列表 listname 中索引值为 index 地位上的元素替换成 newValue。
举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟']
name_list[1] = 'Sarah'
print(name_list)

运行后果:['码农飞哥', 'Sarah', '小小伟'] 从后果能够看出索引为 1 处的元素值被胜利批改成了 Sarch。
第二种:通过切片语法批改一组元素
通过切片语法能够批改一组元素,其语法结构是:listname[start:end:step],其中,listname 示意列表名称,start 示意起始地位,end 示意完结地位(不包含),step 示意步长,如果不指定步长,Python 就不要求新赋值的元素个数与原来的元素个数雷同,这意味着,该操作能够为列表增加元素,也能够为列表删除元素。举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟']
name_list[0:1] = ['飞哥', '牛逼']
print(name_list)

运行后果是:['飞哥', '牛逼', '小伟', '小小伟'],从后果能够看出将原列表中索引为 0 处的元素值曾经被替换为 飞哥 , 并且插入了 牛逼 这个元素。

五浅:删除列表中的元素

删除列表中元素的办法共有四种。
第一种:依据索引值删除元素的 del 关键字
依据索引值删除元素的 del 关键字有两种模式,一种是删除单个元素,del listname[index],一种是依据切片删除多个元素del listname[start : end],其中,listname 示意列表名称,start 示意起始索引,end 示意完结索引,del 会删除从索引 start 到 end 之间的元素,然而不包含 end 地位的元素。还是举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
name_list2 = name_list
print('原始的 name_list={0}'.format(name_list))
print('原始的 name_list2={0}'.format(name_list2))
# 删除索引 0 到 2 之间的元素,即删除索引 0 和索引 1 两个地位的元素
del name_list[0:2]
print('应用 del 删除元素后 name_list={0}'.format(name_list))
print('应用 del 删除元素后 name_list2={0}'.format(name_list2))
del name_list
print('应用 del 删除列表后 name_list2={0}'.format(name_list2))

运行后果是:

原始的 name_list=['码农飞哥', '小伟', '小小伟', '超人']
原始的 name_list2=['码农飞哥', '小伟', '小小伟', '超人']
应用 del 删除元素后 name_list=['小小伟', '超人']
应用 del 删除元素后 name_list2=['小小伟', '超人']
应用 del 删除列表后 name_list2=['小小伟', '超人']

能够看出用 del 删除列表元素时是实在的删除了内存数据的,然而用 del 删除列表时,则只是删除了变量,name_list2 所指向的内存数据还是存在的。
第二种:依据索引值删除元素的 pop()办法
依据索引值删除元素的 pop()办法的语法结构是:listname.pop(index),其中,listname 示意列表名称,index 示意索引值,如果不写 index 参数,默认会删除列表中最初一个元素,相似于数据结构中的出栈操作。举个例子:

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
# 删除 list 开端的元素
name_list.pop()
print(name_list)
# 删除指定地位的元素,用 pop(i)办法,其中 i 是索引地位
name_list.pop(1)
print(name_list)

运行后果是:

['码农飞哥', '小伟', '小小伟']
['码农飞哥', '小小伟']

第三种:依据元素值进行删除的 remove()办法
依据元素值进行删除的 remove()办法, 其语法结构是:listname.remove(object),其中 listname 示意列表的名称,object 示意待删除的元素名称。须要留神的是:如果元素在列表中不存在则会报 ValueError 的谬误。举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
name_list.remove('小小伟')
print(name_list)

运行后果是:['码农飞哥', '小伟', '超人']
第四种:删除列表中的所有元素 clear()办法
通过 clear()办法能够删除掉列表中的所有元素,其语法结构是:listname.clear(),其中 listname 示意列表的名称。还是举个栗子吧:

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
name_list.clear()
print(name_list)

运行后果是:[],能够看出列表中元素被全副清空了。

六浅:列表中元素的查找以及拜访

说完了第五浅列表元素的删除,略感疲乏。接着进行第六浅吧!看看列表中元素的查找以及拜访。看完这个之后,列表相干的内容也就告一段落了。

拜访列表中的元素

拜访列表中的元素有两种形式,别离是通过索引定位拜访单个元素,通过切片拜访多个元素。
第一种:通过索引定位拜访单个元素,其语法结构是:listname[index] , 其中 listname 示意列表的名字,index 示意要查找元素的索引值。
第二种:通过切片的形式拜访多个元素,其语法结构是:listname[start:end:step]。其中,listname 示意列表的名字,start 示意开始索引,end 示意完结索引(不包含 end 地位),step 示意步长。同样是举个栗子:

list = ['码农飞哥', '小伟', '小小伟',123]
print(list[0])  # 输入列表的第一个元素
print(list[1:3])  # 输入第二个至第三个元素
print(list[2:])  # 输入从第三个开始至列表开端的所有元素

运行后果是:

码农飞哥
['小伟', '小小伟']
['小小伟', 123]

查找某个元素在列表中呈现的地位 index()

indext()办法用来查找某个元素在列表中呈现的地位(也就是索引),如果该元素在列表中不存在,则会报 ValueError 谬误。其语法结构是:listname.index(object, start, end) 其中 listname 示意列表的名字,object 示意要查找的元素,start 示意起始索引,end 示意完结索引(不包含)。

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
print(name_list.index('小伟', 0, 2))

运行后果是:1

七浅:列表应用技巧及注意事项

此处留一个空白,欢送小伙伴留言通知我,先看个图放松下吧!!

图片看完之后是不是感觉好多了,那就让咱们接着来学习吧。

Python 新增元素中各个办法的区别

后面介绍了应用 + 运算符,应用 append 办法,应用 extend 办法都能够新增元素,那么他们到底有啥区别呢?还是举例说明吧;

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
name_list2 = ['牛魔王']
name_list3 = name_list + name_list2
print("原始的 name_list 的值 ={0};内存地址 ={1}".format(name_list, id(name_list)))
print("应用 + 运算符后 name_list3 的值 ={0};内存地址 ={1}".format(name_list3, id(name_list3)))
print("应用 + 运算符后 name_list 的值{0};内存地址 ={1}".format(name_list, id(name_list)))
name_list4 = name_list.append('牛魔王')
print('应用 append 办法后 name_list4 的值 ={0};内存地址 ={1}'.format(name_list4, id(name_list4)))
print("应用 append 办法后 name_list 的值{0};内存地址 ={1}".format(name_list, id(name_list)))
name_list5 = name_list.extend('牛魔王')
print('应用 extend 办法后 name_list5 的值 ={0};内存地址 ={1}'.format(name_list4, id(name_list4)))
print("应用 extend 办法后 name_list 的值{0};内存地址 ={1}".format(name_list, id(name_list)))

运行后果是:

原始的 name_list 的值 =['码农飞哥', '小伟', '小小伟', '超人'];内存地址 =2069467533448
应用 + 运算符后 name_list3 的值 =['码农飞哥', '小伟', '小小伟', '超人', '牛魔王'];内存地址 =2069467533896
应用 + 运算符后 name_list 的值['码农飞哥', '小伟', '小小伟', '超人'];内存地址 =2069467533448
应用 append 办法后 name_list4 的值 =None;内存地址 =2012521616
应用 append 办法后 name_list 的值['码农飞哥', '小伟', '小小伟', '超人', '牛魔王'];内存地址 =2069467533448
应用 extend 办法后 name_list5 的值 =None;内存地址 =2012521616
应用 extend 办法后 name_list 的值['码农飞哥', '小伟', '小小伟', '超人', '牛魔王', '牛', '魔', '王'];内存地址 =2069467533448

从运行后果能够看出如下几点:

  1. 应用 + 运算符是创立一个新的列表,新列表的地址与原列表的地址不雷同,并且原始列表的内容不会扭转。
  2. append 办法和 extend 办法都是批改原始列表的内容,并且都没有返回值,所以两者都不能应用链式表达式。
  3. 当待增加的元素是列表时,append 办法会将列表当成一个整体,而 extend 不会。

八浅:元组(tuple)的介绍

说完了列表,接着让咱们来看看另外一个重要的序列 – 元组(tuple),和列表相似,元组也是由一系列按特定书序排序的元素组成,与列表最重要的区别是,元组属于不可变序列,即元组一旦被创立,它的元素就不可更改了。

元组的创立形式

第一种:应用 () 间接创立
应用 () 创立元组的语法结构是tuplename=(element1,element2,....,elementn), 其中 tuplename 示意元组的变量名,element1~elementn 示意元组中的元素。小括号不是必须的,只有将元素用逗号分隔,Python 就会将其视为元组。还是举个栗子:

# 创立元组
tuple_name = ('码农飞哥', '小伟', '小小伟', '超人')
print(tuple_name)
#去掉小括号创立元组
tuple2 = '码农飞哥', '小伟', '小小伟', '超人'
print(type(tuple2))

运行后果是:

('码农飞哥', '小伟', '小小伟', '超人')
<class 'tuple'>

第二种:应用 tuple() 函数创立
与列表相似的,咱们能够通过 tuple(iterable) 函数来创立元组,如果 iterable 传入为空,则创立一个空的元组,iterable 参数必须是 可迭代的序列,比方字符串,列表,元组等。同样的 iterable 不能传入一个数字。举个栗子:

name_list = ['码农飞哥', '小伟', '小小伟', '超人']
print(tuple(name_list))
print(tuple('码农飞哥'))

运行后果是:

('码农飞哥', '小伟', '小小伟', '超人')
('码', '农', '飞', '哥')

因为元组是不可变序列,所以没有批改元素相干的办法,只能对元组中的元素进行查看。查看元素的形式也与列表相似,共两种形式:
第一种:通过索引(index)拜访元组中的元素,其语法结构是 tuplename[index]
第二种:通过切片的形式拜访,其语法结构是:tuplename[start:end:step]
相干参数的形容在此不再赘述了。仍然是举例说明:

tuple_name = ('码农飞哥', '小伟', '小小伟', '超人')
# 获取索引为 1 的元素值
print(tuple_name[1])
#获取索引为 1 到索引为 2 之间的元素值,不包含索引 2 自身
print(tuple_name[0:2])

运行后果是:

小伟
('码农飞哥', '小伟')

元组中的元素不能批改,不过能够通过 + 来生成一个新的元组。

九浅:元组和列表的区别

说完了后面八浅之后,也有点累了。接着说下元组和列表的区别吧。为啥 Python 要另外设置元组这样一个数据结构呢?元组的性能列表不是都能够满足么?所以,这一浅次要是介绍元组的长处,存在即正当,哈哈哈哈。
区别:

  1. 元素是否能够批改?
    列表中的元素能够批改,而元组中的元素不能批改。如果强行批改元组中的元素,你会失去如下谬误:
TypeError: 'tuple' object does not support item assignment
  1. 存储同样数据所占空间
    上面展现初始化一个空列表和一个空元组所占的字节数
>>> listdemo = []
>>> listdemo.__sizeof__()
40
>>> tupleDemo = ()
>>> tupleDemo.__sizeof__()
24

能够看出元组比列表少占用 16 个字节,这是因为列表是动静的,它须要存储指针来指向对应的元素(占用 8 个字节),另外,因为列表中的元素可变,所以须要额定存储曾经调配的长度大小(占用 8 个字节)。然而对于元组,状况就不同了,元组长度的大小固定,其存储元素不可变,所以存储空间也是固定的。总体来说,元组的存储性能要因为列表,存储同样数据所占用空间更小。

  1. 初始化同样数据所需工夫
    大家想一想初始化同样数据的元组和列表,哪个的速度更快呢?是元组还是列表呢?置信大部分人都会抉择元组,那么元组到底快多少呢?上面就用一个例子阐明一下:同样是初始化元素为 1,2,3,4 两个序列。
(python-demo)  root$ python3 -m timeit 'x=(1,2,3,4)'
10000000 loops, best of 3: 0.029 usec per loop
(python-demo)  root$ python3 -m timeit 'x=[1,2,3,4]'
10000000 loops, best of 3: 0.165 usec per loop

初始化元组花了 0.029 秒,初始化话列表花了 0.165 秒,所以,能够得出的论断是初始化一个雷同元素的列表和元组别离所需的工夫,元组的初始化速度要比列表快 5 倍多。

小结

元组有如下长处:元组比列表的拜访和处理速度更快,存储雷同内容所需空间更小。

一深:列表和元组的底层实现

九浅曾经实现了,最初就来一次更深刻的交换吧。知其然更要知其所以然。话不多说,上面就间接从源码层面来看看列表和元组的底层实现。
首先来剖析列表(list),它的具体构造如下所示:

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

PS:列表实现的源码文件是 listobject.h 和 listobject.c。
list 实质上是一个长度可变的间断数组。其中 ob_item 是一个指针列表,外面的每个指针都指向列表中的元素,而 allocated 则用于存储该列表目前被调配的空间大小。
须要留神的是,allocated 和列表的理论空间大小不同,列表理论空间大小是指 len(list)返回的后果,即下面正文中的 ob_size, 示意该列表理论存储了多少个元素,而理论状况是,为了优化存储构造,防止每次减少元素都要从新分配内存,列表预调配的空间 allocated 往往大于 ob_size。他们的关系是 0 <= ob_size <= allocated
接下来在剖析元组,如下所示为 Python3.7 tuple 元组的具体构造:

typedef struct {
    PyObject_VAR_HEAD
    PyObject *ob_item[1];

    /* ob_item contains space for 'ob_size' elements.
     * Items must normally not be NULL, except during construction when
     * the tuple is not yet visible outside the function that builds it.
     */
} PyTupleObject;

PS: 元组(tuple)实现的源码文件是 tupleobject.h 和 tupleobject.c。
tuple 和 list 类似,实质也是一个数组,然而空间大小固定。不同于个别数组,Python 的 tuple 做了许多优化,来晋升在程序中的效率。

总结

本文具体介绍了 Python 内置数据类型中的列表(list)和元组(tuple)。特地是列表,它的新增元素和删除元素的办法很多,各种办法之间还有许多不同,须要在应用时特地留神。对于不波及批改元素操作的场景,优先应用元组。因为它的性能更好,所占空间更少。


为了更好帮忙更多的小伙伴对 Python 从入门到精通,我从 CSDN 官网那边搞来了一套《==Python 全栈常识图谱 ==》,尺寸 870mm x 560mm,开展后有一张办公桌大小,也能够折叠成一本书的尺寸,有趣味的小伙伴能够理解一下。

我是码农飞哥,再次感谢您读完本文
欢送大家关注我的公众号【码农飞哥】。不积跬步,无以至千里,享受分享的高兴

我是码农飞哥,再次感谢您读完本文

正文完
 0