第十章 python3 数据结构

在开始之前我们加深一下对“序列”,“对象”,“引用”概念的理解,不太清楚的朋友可以再了解下:

1什么是序列,Python中都有哪些序列?

序列中的元素都是有序的,拥有自己的编号(即索引值,也叫下标,默认从0开始),可以通过索引值获取序列中对应的元素。

Python总共有6个内置的序列:字符串、Unicode字符串、列表、元组、buffer对象和 xrange 对象。

序列一般可以做这些操作:索引、长度、切片、遍历、组合(序列相加)、检查成员、重复(乘法)、最小值和最大值。

数据类型中字符串string,列表list,元组tuple属于序列类型;

从可变性上讲:字符串string,元组tuple属于不可变序列,列表list属于可变序列。

不可变序列一般不能对添加,修改和删除元素,所以也就没有添加,修改和删除的操作方法。

2什么是对象,什么是引用?

python中一切皆对象。常量,变量,类,函数等等都可以叫对象。

引用一般是指对象的引用,用来间接操作“对象”的,也可以把引用理解为对象的“别名”,一个对象可以有多个别名,也就是说一个对象可以有多个引用;好比我们人来说,一个人就是一个具体的对象,他有学名,小名,还有绰号,都指向的是这个具体的“人”对象。

Python作为一种动态类型的语言,对象和引用是分离的,通过“引用计数”来跟踪记录已经分配的内存;

当一个对象被创建或者被赋值时,它的初始引用计数为1,当有其他变量也被赋值到这个对象时,引用计数就会增加;

当这个对象不再被其它对象引用时,引用计数就会减小,直到等于0时GC就会回收对象,该对象也就被彻底销毁了。

 

 

 我们可以把上面的值“123”理解为“对象”;a,b,c理解成对象“123”的引用。

等号 = 我们通常叫赋值,可以理解成给对象“123”起别名。

a,b,c这三个引用指向同一个内存地址,也可以说这三个引用指向同一个对象,引用本身存储的是一个内存地址。

如果我们把 a 这条引用删除掉,引用计数会减小,其它引用是不受影响的。

当把a,b,c三条引用全部删除掉,引用计数变成0,对象将被GC回收,释放内存。

 

 

 Python中一切皆对象,所以 a,b,c这三条引用我们通常也叫对象。

3简单分析下Python中几个常见的数据结构

列表list,元组tuple,字典dict,集合set;

数据结构

线性表和链表、堆栈和队列、树和二叉树、图、字典和集合、B树、哈希表。

列表list和元组tuple都是由链表(Linked list)实现的,即列表是链表存储结构,这也解释了为什么列表和元组都是有序的。

线性表分为顺序表和链接表两种,链表是线性表中的第二种,所以并不会按线性的顺序存储数据,而是在每一个节点里存着下一个节点的指针。

字典dict和集合set都是由哈希表(hash table)实现,所以都是无序的。

字典dict和集合set都是用空间来换时间,占用空间大,但检索效率高(和元素多少无关);

因为少了key的存储,集合set比字典dict占用的空间相对会小些。

列表list占用空间相对较少,添加和修改元素效率高,但会随着元素个数越来越多,检索查询速度会越来越慢。

元组与列表很类似,不同之处在于元组的元素不能修改,还有列表在创建,变更等操作时需要向系统内核申请空间,元组则是缓存于Python运行时环境中,意味着每次使用元组时无须访问内核去分配内存。

如果想测试一段代码的运行时间可以使用timeit模块:

 

 

 我们可以看出在初始化10个相同元素的列表和元组时,元组要比列表快了6倍多,比用append()初始化列表快了77多倍;遍历时这种速度差距会更大,所以这是元组一个很神奇的地方,它可以轻松快速地创建,就在于元组避免跟操作系统频繁打交道,而列表list需要向系统内核频繁申请空间。

我们再看下列表推导式与普通for循环的性能比较:

 

 

 我们可以看出,实现同样的功能执行1万次,列表推导式要比普通for循环快了4.5秒左右,速度快了2.5倍。所以,推荐大家在以后写代码时优先使用列表推导式;

posted @ 2019-10-13 23:32  在软件技术路上的行者  阅读(91)  评论(0编辑  收藏  举报