2019-02-26 20:41:12 在开始之前我们加深一下对“序列”,“对象”,“引用”概念的理解,不太清楚的朋友可以再了解下: 什么是序列,Python中都有哪些序列? 序列中的元素都是有序的,拥有自己的编号(即索引值,也叫下标,默认从0开始),可以通过索引值获取序列中对应的元素。 Python总共有6个内置的序列:字符串、Unicode字符串、列表、元组、buffer对象和 xrange 对象。 序列一般可以做这些操作:索引、长度、切片、遍历、组合(序列相加)、检查成员、重复(乘法)、最小值和最大值。 数据类型中字符串string,列表list,元组tuple属于序列类型; 从可变性上讲:字符串string,元组tuple属于不可变序列,列表list属于可变序列。 不可变序列一般不能对添加,修改和删除元素,所以也就没有添加,修改和删除的操作方法。 什么是对象,什么是引用? python中一切皆对象。常量,变量,类,函数等等都可以叫对象。 引用一般是指对象的引用,用来间接操作“对象”的,也可以把引用理解为对象的“别名”,一个对象可以有多个别名,也就是说一个对象可以有多个引用;好比我们人来说,一个人就是一个具体的对象,他有学名,小名,还有绰号,都指向的是这个具体的“人”对象。 Python作为一种动态类型的语言,对象和引用是分离的,通过“引用计数”来跟踪记录已经分配的内存; 当一个对象被创建或者被赋值时,它的初始引用计数为1,当有其他变量也被赋值到这个对象时,引用计数就会增加; 当这个对象不再被其它对象引用时,引用计数就会减小,直到等于0时GC就会回收对象,该对象也就被彻底销毁了。 我们可以把上面的值“123”理解为“对象”;a,b,c理解成对象“123”的引用。 等号 = 我们通常叫赋值,可以理解成给对象“123”起别名。 a,b,c这三个引用指向同一个内存地址,也可以说这三个引用指向同一个对象,引用本身存储的是一个内存地址。 如果我们把 a 这条引用删除掉,引用计数会减小,其它引用是不受影响的。 当把a,b,c三条引用全部删除掉,引用计数变成0,对象将被GC回收,释放内存。 Python中一切皆对象,所以 a,b,c这三条引用我们通常也叫对象。 今天我们简单分析下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倍。所以,推荐大家在以后写代码时优先使用列表推导式; |
|