第五章:深入Python的set和dict

1. collections.abc模块介绍

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 10:57'

from collections.abc import Mapping,MutableMapping
# dict是属于Mapping类型的
a = {}
print(type(a)) # dict
print(isinstance(a,MutableMapping)) # 是属于MutableMapping类型的
# 但是它不是通过继承的方式,而是实现了这个类中的一些方法,通过MutableMapping.register(dict)的方法

2.字典的常见操作

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 11:04'
a = {'bob1': {'company': 'imooc'},
     'bob2': {'company': 'imooc2'}}
# clear 清空
# print(a)

# copy,浅拷贝,只拷贝了最外层的对象的引用,如果浅拷贝的
# 时候有可变对象的应用,则如果修改了原来的值,则可变对象的值也就跟着改变.
# 比如上面的a字典,key的拷贝不会出现问题.但是value的值本身也是一个引用类型,
# 它是可变的,拷贝的时候只是拷贝了这个内部字典的应用.所以如果它修改了,则原来的那个
# 对象也会跟着修改.
new_dict = a.copy()
new_dict['bob1']['company'] = 'imooc3'
print(a)
print(new_dict)
# {'bob1': {'company': 'imooc3'}, 'bob2': {'company': 'imooc2'}}
# {'bob1': {'company': 'imooc3'}, 'bob2': {'company': 'imooc2'}}

# fromkeys 将一个可迭代对象作为键,设定一个默认值,生成一个新字典
lst_keys = [1, 2, 3, 4]
new_dict = dict.fromkeys(lst_keys, 'a')
print(new_dict)

# get 根据键获取值.类似dict[key] 的用法.
# 但是dict[key]用法有一个缺点,如果元素不在字典中会创建一个新的键

value = new_dict.get(1, '')  # 如果key为1的不存在或者没有这个key,就会返回空
print(new_dict)
# value = new_dict[5] # 这里会报错
new_dict[5] = 6  # 这里会重新创建一个键,只有这个键存在的时候才是修改对应的值
print(new_dict, new_dict[5])

# items()key,value的元组的列表
print(new_dict.items(), new_dict.keys(), new_dict.values())
# items()返回的是一个元组列表, keys()返回的是键的列表,values()返回的值列表

for key, value in new_dict.items():
    print(key, value)

# setdefault('7','d')  创建一个键,并且设置默认值
default_value = new_dict.setdefault(7, 'd')
print(new_dict)

# update() 可以将一个字典或者一个赋值表达式,或者一个元组列表合并到字典中
new_dict.update({8: 'a'})
new_dict.update(boby=3, boby2=4)
new_dict.update([(9, 'f'), (10, 'g')]) # 放一个元组列表
print(new_dict)

3.和字典相关的类

1. 当我们要自定义一个字典的时候,不要使用直接继承自dict,因为有些操作会不生效

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:42'


class MyDict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value * 2)

my_dict = MyDict()
my_dict['a'] = 3  # 这个时候调用的是__setitem__方法
print(my_dict) # {'a': 6}

# 直接在构造函数中初始化字典,这个时候调用的应该是__call__方法
my_dict = MyDict(b=5)
print(my_dict) # {'b': 5}

# 所以最好不要继承dict的方式,可以用继承collections模块的UserDict的方式

2. 使用继承UserDict的方式来实现自定义的字典.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:47'
from collections import UserDict


class MyDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value * 2)

mydict = MyDict(a=4)
print(mydict)

mydict['b'] = 5
print(mydict)

3. 创建带有默认值的字典. collections中的defaultdict
字典之所以可以实现带有默认值,其实是它内部实现了__missing__方法,在UserDict类里面的__getitem__方法中会调用__missing__方法

    def __getitem__(self, key):
        if key in self.data:
            return self.data[key]
        if hasattr(self.__class__, "__missing__"):
            return self.__class__.__missing__(self, key)
        raise KeyError(key)

defaultdict之所以可以设置默认值就是因为实现了__missing__方法

4. set和frozenset

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:58'
# set 集合 frozenset(不可变集合),无序,不重复
s = set('abcdef')
print(s)
s1 = set(['a', 'b', 'c', 'd'])
print(s1)
# 通过大括号的方式直接赋值
s2 = {'a', 'b', 'c', 'd'}
print(s2)

# 1.集合可以添加元素
s2.add('f')
print(s2)

s = frozenset('abcde')  # frozenset 是不可变的集合,可以作为字典的key
# s.add() 错误,不可变集合不能添加数据

# 2.clear() 清空集合
# 3.copy() 浅拷贝集合
# 4.pop() 弹出最后一个元素
# 5.remove() 删除一个集合元素
# 6.update()像set中添加一个集合
another_set = set('123')
s2.update(another_set)
print(s2)
# 7.difference(找不同)
ret_set = s2.difference(another_set)  # s - s2
print(ret_set)
# 8.求交集 &
ret_set = s2 & another_set
print(ret_set)
# 9.求并集
ret_set = s2 | another_set
print(ret_set)
# 10 in 对应的魔法方法__contains__
if 'a' in ret_set:
    pass
# 11. 判断是否是子集
if s2.issubset(another_set)

5. dict和set的实现原理

dict和list的性能对比:
1. dict的性能远远大于list
2. list的查找时间,hi随着list的数据的增多成正比例增加
3. 而dict的查找时间,不会随着字典的增大而增大.

字典的内部是通过hash表来映射的,什么是hash表,通过字典的key算出一个hash值,这个hash值对应一个位置,这个位置存放着字典的key和value.而因为hash表的存放是连续的,类似于数组,它查找和存取是根据偏移量来进行的,所以不需要遍历,就会速度很快.

注意:
set的值和字典的键的实现原理是一样的,都是可以hash的.
不可变对象,都是可hash的.str,forzenset,tuple,自己实现的类实现了__hash__都是可hash的对象.都可以作为字典的键

dict的内存花销大,但是查询速度快,自定义对象,或者python的自定义对象,都是用字典的方式来存储的.

dict的存储顺序和元素的添加顺序有关
dict中添加元素的时候,有可能会改变原来的位置.当插入的数据过多,重新分配内存的时候,dict就有可能将原来的顺序打乱.
所以一般使用dict的时候,不要期望它会一直维持某种顺序.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容