Python的数据结构
俗话说的好:工欲善其事,必先利其器。要想在Python的国度中畅行无阻,那就必须掌握理解Python的基本数据。就像我们造房子一样,不同的材料有不同的作用,只有了解掌握了不同材料的不同特性并加以运用,我们才能把房子造的更大更漂亮更牢固,所以说掌握基础数据类型的特性是必不可少的。
在此之前的文章简单介绍了很多Python的基础数据类型 ,现在我对这些基础数据类型做一个知识整合,更加系统的掌握Python的基础数据类型。
一.Python数据类型的几个特性
迭代__iter__
迭代,是重复反馈过程的活动,每一次对过程的重复称为一次“迭代”。突然冒出一个迭代,这迭代有什么作用咧?
别急,下面我们来看一段代码:
nums = 123
for num in nums:
print(num)
出现如下错误:
for num in nums:
TypeError: ‘int’ object is not iterable
这个异常错误表示整型不可迭代。
哦,原来是否可迭代是在用于循环时是否可重复引用,迭代意味着对每个元素执行特定的操作,只有能迭代才使用in的操作符,那么可以看出整型对象是不具备迭代性质滴,那么什么才具备迭代性质咧?我们说一个对象是否可迭代,看对象的属性或方法中是否内置迭代器,只有可迭代的对象才能进行for…in…等循环引用,比如str,tuple,list,dict等序列
哈希值__hash__
哈希值,等等,这又是什么东东??
我们来取自百度的定义:用一个具有映射关系的散列函数,将数据打乱混合,重新创建一个值叫做散列值,也叫做哈希值。
哦,那他有什么作用咧?它的作用就大咯,因为具有可以将一堆的数据打乱成一个值的原因,所以具有可压缩的作用,并且如果散列函数选的好,那么哈希值通常是唯一的,所以可以对应唯一的内存地址值,就像你家其实就是唯一的一个地址,不能说找小王的家,却指到小刘的家对吧?那自然可以利用哈希值建立映射关系来存储数据,只要我们给出唯一的哈希值就可以立刻读取到这个哈希值的内存地址,可以一步到位进行插入,查找,删除操作。
展示一下哈希值的代码:
nums = 'aabc'
for num in nums:
print(num.__hash__())
输出的是:
-7261026270066357492
-7261026270066357492
-4271918388016019200
-4255412755611172810
看到了同样的字符对应同样的哈希值,不同的字符哈希也不一样。
所以利用哈希值的特性构成了哈希表,应用了哈希值映射对象存储地址,Python中字典的构成原理其实就是哈希表,由键值的哈希值映射到值的地址;另外的应用如检测文件数据是否更改,数据丢失;还有个发家致富作用当然就是挖比特币了,哈哈哈…Python中内置的不可修改数据类型都具有可哈希的特性,哈希表实现存储的数据结构都是无序的,这是哈希值的特性所决定的
有序和无序
Python中有很多序列,其中序列分为无序和有序两种,那么影响序列有序和无序的关键因素是什么呢?Python不同的数据类型是由不同的数据结构实现的,数据结构包括数组,链表,树,表,图等,而这些数据结构的一些特性决定了Python数据类型有序性或无序性。比如字符串是由静态数组实现的,所以其有序;字典是由哈希表实现,所以其无序,我们有的时候打印键值对时会发现其的顺序是乱的。
可变对象与不可变对象
上一篇文章我们介绍对象与引用时,我们指出变量其实是对象的引用。
所谓可变与否,则是当变量发生改变时,对象的内容是否发生改变。所以可变对象是内容可变的对象,不可变对象是内容不可变的对象。
比如:
可见,不可变对象内容是不变的,变的是变量引用的地址。
而可变对象的内容是可变的,对象的引用不会改变。
i=[1,2]
print(id(i))
print('i = {}'.format(i))
i+=[3] #这里注意不要直接让i=[1,2,3];这会使i指向一个新的列表对象
print(id(i))
print('i = {}'.format(i))
139985579385160
i = [1, 2]
139985579385160
i = [1, 2, 3]
所以可变对象,变量内容发生改变,引用不变。
那么可变,可哈希,可修改之间有什么关系?
上面我们说了可变对象内容可修改,不可变对象内容不可修改。而哈希值是根据对象内容映射出来的一个值,对于可变对象的内容无时无刻都可能在变化,自然是做不到一个对象有唯一哈希值,所以可变对象不可哈希,不可变对象可哈希(不是绝对的)。
不可变对象–>内容不可修改–>可哈希
可变对象–>内容可修改–>不可哈希
复合,嵌套数据类型的特性
当然,说到可迭代,可哈希,可修改和其他一些特性是指对象本身而言。而对于对象的内容是否可迭代,可哈希,可修改,这个主要看内容本身是什么数据类型的对象,对象里的内容也会修改对象本身的一些特性,要客观的看待。
比如列表[1,2,3],其实是由整型组合而成,列表本身不可哈希,可列表中的内容是可哈希的。又比如元组里嵌套列表,列表的值是可以修改的,归根到底是元组说的不变是对象的引用不变,而不是对象的内容不变。(放下一个疑问,为什么元组里嵌套列表,列表可以append()添加元素,却不可以+=[]添加)
复杂的数据类型,也是由最基础的数据类型组合而成,组合之后其一些特性是不变的。像砌房子,砖头还是那块砖头,可能是外形颜色变了,其固有的一些特性是不变的,但材质的特性也会影响改变房子的性能,结构。某些房子可能只能用特定的材质组成,这就有了一些复合数据类型只能存放一些特定的数据类型。
二.Python的基础数据类型
了解了上面几个特性以后,我们对Python基础数据类型的一些特点有了解,下面我们对Python的数据类型做个简单的分类,并描述一类数据结构所含有的一些特性,能帮助我们更好的了解基础数据类型,在开发当中更好的选取合适的数据结构。
1.数字
性质:不可变,可哈希,不可迭代,不可修改
整型
浮点型
布尔型
复数型
2.序列
序列的通用操作:
索引,成员资格检查,迭代
注意:set集合不支持索引,字典支持键值索引
有序序列的通用操作:
切片,相加,相乘
字符串
性质:有序序列,不可变,可哈希,可迭代,不可修改
ASCAII编码
UTF-8编码
UNICODE编码
集合
集合类型 | 性质 | 存放数据 |
---|---|---|
set集合 | 无序序列,可变,不可哈希,可迭代,可修改,具有去重性的性质,以哈希表形式实现 | 存放不可变的数据类型 |
frozenset集合 | 无序序列,不可变,可哈希,可迭代,不可修改,以哈希表形式实现,相当于不可修改的set集合 | 存放不可变的数据类型 |
tuple元组 | 有序序列,不可变,可哈希,可迭代,不可修改,以静态数组形式实现,性能更好,可以作为字典的键 | 基础数据类型都能存放 |
list列表 | 有序序列,可变,不可哈希,可迭代,可修改,以动态数组形式实现 | 基础数据类型都能存放 |
dict字典 | 默认无序序列,可变,不可哈希,可迭代,可修改,以哈希表形式实现 | 基础数据类型都能存放 |
如何获取一个对象是什么类型呢,可用下面两条函数操作:
输出数据类型,返回数据类型 type(data)
检验数据类型,返回布尔值 isinstantce(data,type)
序列的索引,切片,相加,相乘,成员资格
序列的索引
序列中的所有元素都有编号,可以通过编号的方式访问各个元素,从编号0开始递增,编号不能大于等于序列的大小
a = ‘abc’
a[0] = ‘a’
Python中编号为负数时是合法的,它的意义是从序列最大编号开始倒数,从编号-1开始递减,编号的绝对值不能大于序列大小
a = ‘abc’
a[-1] = c
序列的切片
切片的表达式[起始:终止:步长]
1.当起始为序列开头时,起始索引可省略
2.当终止为序列结尾时,终止索引可省略
3.若需要不是1的步长时,可添加步长,注意步长不能为0
4.终止索引和起始索引不同号时,最好先转换,防止没有交集。
5.步长为正时,从左到右切出元素,起始索引必须比终止索引小。
6.步长为负数,从右到做切出元素,起始索引必须比终止索引大。
a =‘abcde’
a[1:2] = ‘bc’
a[:4] = ‘abcde’
a[1:] = ‘bcde’
a[:] = ‘abcde’
a[:-1]= ‘abcde’
a[-2:-1] =‘de’
a[4:1:-1]=‘edcb’
序列相加和序列乘法(序列的连接与序列的复制)
不同的序列可以通过 ‘+’运算符相加扩展,需要注意的是相加是同一类型的序列,如字符串不能和列表相加
a = ‘abc’
b = ‘def’
a+b = ‘abcdef’
将序列通过‘*’运算符与数n相乘,可以复制n次
[1]*3=[1,1,1]
序列的成员资格
要检查特定的值是否在序列中,可以使用运算符in
a = ‘abc’
‘a’ in a
输出为:True
‘d’ in a
输出为:False
三.Python常用数据结构的操作方法
了解数据结构的特性,我们来整理一下常用数据结构的一些操作方法,以便在开发过程中查找使用。
1.元组(tuple)
元组的常用操作
基本操作 | 操作功能描述 |
---|---|
len(tuple) | 元组长度 |
max(tuple) | 元组元素最大值 |
min(tuple) | 元组元素最小值 |
tuple(seq) | 生成一个元组 |
元组操作 | 操作功能描述 |
---|---|
tuple.count(obj) | 统计元组某个元素的元素个数 |
tuple.index(obj) | 统计元组某个元素的索引 |
2.列表(list)
列表的常用操作
list()传入对象必须为可迭代对象,python中整型,浮点数,不可迭代,单个字符和字符串是可迭代
基本操作 | 操作功能描述 |
---|---|
len(list) | 列表长度 |
max(list) | 列表元素最大值 |
min(list) | 列表元素最小值 |
list(seq) | 生成一个列表 |
列表操作 | 操作功能描述 |
---|---|
list.append(obj) | 在列表的末尾添加元素 |
list.clear() | 清除列表元素 |
list.copy() | 列表复制一个副本 |
list.count(obj) | 统计列表某个元素的元素个数 |
list.extend(seq) | 列表末尾扩展列表 |
list.index(obj) | 获取列表某元素的索引 |
list.insert(index,obj) | 在列表中插入元素 |
list.pop(index) | 列表输出某一个元素并删除 |
list.remove(obj) | 列表移除某一元素 |
list.reverse() | 列表反转 |
list.sort() | 对列表排序 |
3.字典(dict)
字典的常用操作
基本操作 | 操作功能描述 |
---|---|
len(dict) | 字典长度 |
str(dict) | 打印字典 |
字典操作 | 操作功能描述 |
---|---|
dict.clear() | 清除字典 |
dict.copy() | 复制字典副本 |
dict.fromkeys() | 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
dict.get(key,default=None) | 返回指定键的值,如果不存在的键返回一个default值 |
dict.items() | 返回一个列表,元素为字典的(键, 值) 元组序列 |
dict.keys() | 返回一个迭代器记录键值 |
dict.pop(key) | 删除对应键值对 |
dict.popitem() | 随机删除一对键值 |
dict.setdefault(key,default=None) | 如果不存在的键,将会添加键并将值设置为default值 |
dict.update(dict2) | 将字典dict2的键值对更新到字典dict上 |
dict.values() | 返回一个迭代器记录值 |
4.集合(set)
集合的常用操作
基本操作 | 操作功能描述 |
---|---|
len(set) | 集合长度 |
set.add(obj) | 为集合添加元素 |
set.clear() | 移除集合中的所有元素 |
set.copy() | 拷贝一个集合 |
set.difference() | 返回多个集合的差集 |
set.difference_update() | 移除集合中的元素,该元素在指定的集合也存在。 |
set.discard() | 删除集合中指定的元素 |
set.intersection() | 返回集合的交集 |
set.intersection_update() | 删除集合中的元素,该元素在指定的集合中不存在。 |
set.isdisjoint() | 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。 |
set.issubset() | 判断指定集合是否为该方法参数集合的子集。 |
set.issuperset() | 判断该方法的参数集合是否为指定集合的子集 |
set.pop(obj) | 移除指定元素 |
set.remove(obj) | 移除指定元素 |
set.symmetric_difference() | 返回两个集合中不重复的元素集合。 |
set.symmetric_difference_update() | 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。 |
set.union() | 返回两个集合的并集 |
set.update() | 给集合添加元素 |