Q1 字典有什么特点?
Q2 什么时候需要用到字典数据类型?
Q3 字典好像有键值对,具体有什么什么样子的?
Q4 字典如何在内存中存储的呢?是一块内存中分为两部分,一部分存储key,一部分存储value?
Q5 集合有并、交、差操作吗?
Q6 一个key 能对应多个value吗?一个value 能对应多个key吗?
我猜测key一对多value不行,但是多个键可以有同一个值,有点像数学中的函数 x与y的关系。可是意义不大啊。比如name 和 age 这个值明显不一样嘛。
Q7 满足什么条件才能作为键?
A1
字典是一个键/值对的集合,是无序的,且可变的。
A3
>>> a = {'name':'xiaoming','age':20,'job':'programmer'} # >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer'} >>> type(a) <class 'dict'>
>>> b = dict(name = 'xiaoming', age=18, job = 'programmer') >>> b {'name': 'xiaoming', 'age': 18, 'job': 'programmer'} >>> type(b) <class 'dict'>
>>> k = ['name','age','job'] >>> v = ['xiaoing',18,'programmer'] >>> c = dict(zip(k,v)) >>> c {'name': 'xiaoing', 'age': 18, 'job': 'programmer'} >>> type(c) <class 'dict'>
>>> d = dict.fromkeys(['name','age','job']) >>> d {'name': None, 'age': None, 'job': None} >>> type(d) <class 'dict'
还是{} 和dict() 方法创建简单
>>> a = {'name':'xiaoming','age':20,'job':'programmer'} >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer'} >>> a['name'] 'xiaoming' >>> a['id'] Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> a['id'] KeyError: 'id'
>>> a.get('name') 'xiaoming' >>> a.get('age') 20 >>> a.get('id') #不存在的i键 返回None >>> a.get('id', 1234567) #可以指定返回内容 1234567
>>> a.items() dict_items([('name', 'xiaoming'), ('age', 20), ('job', 'programmer')])
>>> a.keys() dict_keys(['name', 'age', 'job']) >>> a.values() dict_values(['xiaoming', 20, 'programmer'])
>>> a.keys() dict_keys(['name', 'age', 'job']) >>> len(a) 3
>>> 'id' in a False >>> 'name' in a True
>>> a['id'] = 12345678 >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'id': 12345678}
>>> b = {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'id': 12345678, 'sex': 'man'} >>>> a.update(b) >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'id': 12345678, 'sex': 'man'}
>>> del(a['sex']) >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'id': 12345678}
>>> a.pop('id') 12345678 >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer'}
>>> a.popitem() ('test2', 'test2') >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'test1': 'test1'}
>>> a1 = a >>> a1 {'name': 'xiaoming', 'age': 20, 'job': 'programmer', 'test1': 'test1'} >>> id(a1) 2239422203328 >>> id(a) 2239422203328 >>> a1.clear() >>> a1 {} >>> a {}
>>> a = {'name': 'xiaoming', 'age': 20, 'job': 'programmer'} >>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer'} >>> name, age, job = a >>> name 'name' >>> age 'age' >>> job 'job
>>> name, age, job = a.values() >>> name 'xiaoming' >>> age 20 >>> job 'programmer'
键值对 items() 以键值对返回
>>> name, age, job = a.items() >>> name ('name', 'xiaoming') >>> age ('age', 20) >>> job ('job', 'programmer') >>> type(name) #注意返回的类型是元组 <class 'tuple'> >>> type(age) <class 'tuple'> >>> type(job) <class 'tuple'>
A4
字典对象的核心散列表(稀疏数组),数组的每个单元 叫做一个bucket,bucket 分为两部分 一个是key对象的地址,一个是值对象的地址。通过hash()方法存键取值,具体细节部分,如下。
存的过程主要解决如何让这个key 放到对应的bucket索引中去,如图:
过程如下:
首先用hash()计算出key的散列值(二进制表示),然后从右往左依次取k位二进制,将这k位二进制转为十进制,记为i,如果i对应的bucket为空,则存放;如果不为空,再次向左侧取k位二进制。如果bucket满了,超过2/3时会自动扩容。
如何计算这个k呢?bucket为8时,k为3,bucket为16时,k为4。依次类推。
>>> a {'name': 'xiaoming', 'age': 20, 'job': 'programmer'} >>> bin(hash("name")) #计算出name的散列值,以二进制表示 '-0b1111001100101101011101101100100001110010100000110100011100110'
流程图如下:
那就有个疑问了,bucket的空间要是不是 2^k 怎么办呢? 还是说bucket默认创建的空间就是2^k 。会不会太浪费内存了呢?
我猜测这个内存默认开辟空间为2^k大小,且是根据实际自己电脑具体位数,来计算的。
比如我里面只有2个键值对,实际能存可能是能存放8个,如果是9个键值对,实际开辟的大小是16。
这字典是以空间换时间。读取数据快。
当我们用get(“name”)找到对应的值时,首先还是会计算这个键的散列值,然后依然是从右向左取k位二进制数,转为十进制数位i,如果i位空,返回None;如果不为空,需要计算对应此时已经存储i索引的键的散列值,与当前的对象进行判断,如果相等,取出值;如果不相等,则向左再取k个二进制,进行计算,直到结束。
如图所示:
流程图:
A6
a = {"name":"xiaoming","name":"xiaohong","age":20} >>> a {'name': 'xiaohong', 'age': 20} # 键名称为name的只有一个。满足集合的特点。
A7
键必须是可散列的。
满足两个条件称为"可散列":
1、具有__hash__方法 ,可将一个类型映射为一个int值,且在一个生命周期中保持不变。
2、具有__eq__方法,能够判断两个对象是否相等。
>>> a = {1,2,3,4,5,5,5,5} >>> a {1, 2, 3, 4, 5}
>>> a = set([1,2,3,4,5,5,5]) >>> a {1, 2, 3, 4, 5} >>> a = set((1,2,3,4,5,6,6,7,7,7)) >>> a {1, 2, 3, 4, 5, 6, 7}
>>> a {1, 2, 3, 4, 5, 6, 7} >>> >>> a.add(8) >>> a {1, 2, 3, 4, 5, 6, 7, 8}
>>> a {1, 2, 3, 4, 5, 6, 7, 8} >>> a.remove(1) >>> a {2, 3, 4, 5, 6, 7, 8} >>> a.clear() >>> a set()
A5
>>> a = {1,2,3} >>> b = {4,5,6} >>> c = {1,2,3,4,5,6} >>> a | b {1, 2, 3, 4, 5, 6} >>> a & b set() >>> a - b {1, 2, 3} >>> b - a {4, 5, 6} >>> a & c {1, 2, 3} >>> b & c {4, 5, 6} >>> a.union(b) {1, 2, 3, 4, 5, 6} >>> a.intersection(b) set() >>> a.difference(b) {1, 2, 3}
无序、无重复、可变
数据类型 | 有序无序 | 是否可变 | 各自特点 |
---|---|---|---|
列表 | 有序 | 可变 | 像是升级的顺序表 |
元组 | 有序 | 不可变 | 受到限制的列表 |
字典 | 无序 | 可变 | 键值对,是特殊的集合,无重复元素 |
集合 | 无序 | 可变 | 只有键,无值,无重复元素 |
>>> a = [ ['xiaoming', 20, '20330801', 'm'], ['xiaohong', 20, '20300802', 'f'], ['xiaogang', 20, '20300803', 'm'], ] >>> a [['xiaoming', 20, '20330801', 'm'], ['xiaohong', 20, '20300802', 'f'], ['xiaogang', 20, '20300803', 'm']] >>> d1 = {"name":"xiaoming","age":20,"salary":30000,"location":"beijing"} >>> d2 = {"name":"xiaohong","age":20,"salary":20000,"location":"shanghai"} >>> d3 = {"name":"xiaogang","age":20,"salary":15000,"location":"hangzhou"} >>> >>> td = [d1,d2,d3] >>> td [{'name': 'xiaoming', 'age': 20, 'salary': 30000, 'location': 'beijing'}, {'name': 'xiaohong', 'age': 20, 'salary': 20000, 'location': 'shanghai'}, {'name': 'xiaogang', 'age': 20, 'salary': 15000, 'location': 'hangzhou'}]