python互相关函数_python数据类型及底层原理


可变和不可变

不可变类型:数字、字符串、元组、frozenset

可变类型:列表、字典、集合

这里的可变和不可变是指内存中的那块内容,是否可以被改变。如果是不可变类型,在对对象操作时必须重写开辟一块新内存(因为老旧区域不可变)。如果时可变类型,对对象操作时,不需要在其他地方申请内存

深拷贝与浅拷贝

深拷贝

深拷贝就是将一个对象拷贝到另一个对象中,这意味这你对一个对象的拷贝做出改变时,不会影响原对象。两者之间互不影响。

f2ab099f665dd52e7c846a1d1e8518b0.png

你抓鲁迅和我周树人有什么关系?

da764a724b8df86b32bcdf4bb61d1087.png

而浅拷贝是将一个对象的引用拷贝到另一个对象上,所有我们在拷贝中改动,会影响到原对象

81d42467ef35ddc8318337544c74496e.png

切片操作时浅拷贝

工厂函数时浅拷贝: lst1 = list(lst)

浅拷贝要分三种情况进行讨论
  • 拷贝不可变对象:只是增加一个指向原对象的引用,改变会互相影响
>>> a = (1, 2, [3, 4])>>> b = copy.copy(a)>>> b... (1, 2, [3, 4])# 改变一方,另一方也改变>>> b[2].append(5)>>> a... (1, 2, [3, 4, 5])
  • 拷贝可变类型(一层结构):产生新的对象,开辟新的内存空间,改变互不影响
>>> import copy>>> a = [1, 2, 3]>>> b = copy.copy(a)>>> b... [1, 2, 3]# 查看两者的内存地址,不同,开辟了新的内存空间>>> id(b)... 1833997595272>>> id(a)... 1833997595080>>> a is b... False# 改变了一方,另一方关我卵事a = [1, 2, 3]    b = [1, 2, 3]>>> b.append(4)>>> a... [1, 2, 3]>>> a.append(5)>>> b... [1, 2, 3, 4]
  • 拷贝可变类型(多层结构):产生新的对象,开辟新的内存空间,不改变包含的子对象则互不影响,改变包换的子对象则相互影响
>>> import copy>>> a = [1, 2, [3, 4]]>>> b = copy.copy(a)>>> b... [1, 2, [3, 4]]# 查看两者的内存地址,不同,开辟了新的内存空间>>> id(b)1833997596488>>> id(a)1833997596424>>> a is b... False# 1.没有对包含的子对象进行修改,另一方关我卵事a = [1, 2, [3, 4]]    b = [1, 2, [3, 4]]>>> b.append(5)>>> a... [1, 2, [3, 4]]>>> a.append(6)>>> b... [1, 2, [3, 4], 5]# 2.对包含的子对象进行修改,另一方也随之改变a = [1, 2, [3, 4]]    b = [1, 2, [3, 4]]>>> b[2].append(5)>>> a... [1, 2, [3, 4, 5]]>>> a[2].append(6)>>> b... [1, 2, [3, 4, 5, 6]]
列表的底层实现

实现细节 python中的列表的英文名是list,因此很容易和其它语言(C++, Java等)标准库中常见的链表混淆。事实上CPython的列表根本不是列表(可能换成英文理解起来容易些:python中的list不是list)。在CPython中,列表被实现为长度可变的数组。

从细节上看,python中的列表是由其他对象的引用组成的连续数据。指向这个数组的指针及长度被保存在一个列表头结构中。也就是说每次添加或删除一个元素时,由引用组成的数据需要重写标记标大小。但在python中创建一个列表时,采用了指数过分配,所有并不是每次操作都需要改变数组的大小,因为这个原因,添加或取出元素的平坦复杂度极低。

通俗点说就是当列表被创建时它会申请一个比自身要大的内存,当自身的内存与申请的内存相同后,它会在申请一个内存然后将之前所有的数据都拷贝进去。

但在使用insert方法在任意位置插入一个元素它的时间复杂度为O(n),使用pop或remove删除一个元素复杂度也是O(n)

列表推导

要习惯用列表推导,因为这更加高效和简短,涉及的语法元素少。在大型的程序中,这意味着更少的错误,代码也更容易阅读。

>>>[i for i in range(10) if i % 2 == 0]
    [0, 2, 4, 6, 8]

1.使用enumerate.在循环使用序列时,这个内置函数可以方便的获取其索引:

>>> for i, element in enumerate(["one","two","three"]):
...     print(i, element)
...
0 one
1 two
2 three
元组底层实现

元组和列表相似,本质也是一个数组,但是空间大小固定(不可变),不同于数组,python的元组做出了许多优化,来提升在程序中的效率

为了提高效率,避免频繁调用系统函数free和malloc向操作系统审批和释放空间,元组源文件中定义了一个free_list所有申请过的,小于一定大小的元组,在释放的时候会被放在这个free_list中,以供下次使用,也就是说如果以后在创建相同的元组,可以直接从缓存中载入

字典的底层实现

字典底层是维护一张哈希表,我们可以把它看成一个列表,列表的每个元素都存了哈希值、键、值三个元素,还需要一个indices表来辅助

indices = [None, None, index, None, index, None, index]
enteies = [
    [hash0, key0, value0],
    [hash1, key1, value1],
    [hash2, key2, value2]
]

计算key的哈希值,在减去mask(字典的最小长度-1)得到一个数字,这个数字就是要插入的indices的下标位置

得到index值后会找indices的位置,但是此位置不是存的哈希值,而是存的len(enteies),表示该值在enteies的位置

如果出现了hash冲突则向下一个查找,直到不冲突为止

# 给字典添加一个值,key为hello,value为wordmy_dict['hello'] = 'word'# 假设是一个空列表,hash表初始如下indices = [None, None, None, None, None, None]
enteies = []

hash_value = hash('hello')  # 假设值为 12343543index = hash_value & ( len(indices) - 1)  # 假设index值计算后等于3,具体的hash算法本文不做介绍# 会找到indices的index为3的位置,并插入enteies的长度indices = [None, None, None, 0, None, None]# 此时enteies会插入第一个元素enteies = [
    [12343543, 'hello', 'word']
]# 我们继续向字典中添加值my_dict['haimeimei'] = 'lihua'hash_value = hash('haimeimei')  # 假设值为 34323545index = hash_value & ( len(indices) - 1)  # 假设index值计算后同样等于 0# 会找到indices的index为0的位置,并插入enteies的长度indices = [1, None, None, 0, None, None]# 此时enteies会插入第一个元素enteies = [
    [12343543, 'hello', 'word'],
    [34323545, 'haimeimei', 'lihua']
]
列表与元组的区别

首先列表是可变的,元组是不可变的

元组的大小是固定的,列表是在会动态变化得

所有在效率上,元组是列表快得,

元组可以用来存储一个人得身高体重年龄等信息,或者记录某个坐标

列表可以存储多条数据,[“zhangsan”,”lisi”]

列表和字典的区别

list是有序的,dict在python3.6以后变为有序的

list通过索引取值,而dict通过键取值,dict取值更快

list随着数量的增加要查找的元素的话时间更旧,O(n),dict不会随着数量变化而变化,时间复杂度都是O(1)

dict占用的空间要比list大,可能大1.5倍

特征决定用途:

list一般可作为队列、堆栈使用,而dict一般作为聚合统计或者快速使用特征访问等

集合的底层实现

python的内置集合类型有两种:

set(): 一种可变的、无序的、有限的集合,其元素是唯一的、不可变的(可哈希的)对象。 frozenset(): 一种不可变的、可哈希的、无序的集合,其元素是唯一的,不可变的哈希对象。

set里的元素是不可变的,唯一的,但是set是可变的,所以set作为set的元素会报错

cpython中集合和字典非常相似,事实上,集合被实现带有控制的字典,只有键才是实际的集合元素。

可以快速的向集合中添加元素,删除元素,检查元素是否存在。平均时间复杂度为O(1),最坏为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值