返回顶部

05 python深入python的set和dict

dict的abc继承关系

dict属于mapping类型,下面通过查看源码来分析它的继承关系

from collections.abc import Mapping, MutableMapping

查看MutableMapping源码

class MutableMapping(Mapping):

    __slots__ = ()

    """A MutableMapping is a generic container for associating
    key/value pairs.

    This class provides concrete generic implementations of all
    methods except for __getitem__, __setitem__, __delitem__,
    __iter__, and __len__.

    """

    @abstractmethod
    def __setitem__(self, key, value):
        raise KeyError

    @abstractmethod
    def __delitem__(self, key):
        raise KeyError

    __marker = object()

    def pop(self, key, default=__marker):
        '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
          If key is not found, d is returned if given, otherwise KeyError is raised.
        '''
        try:
            value = self[key]
        except KeyError:
            if default is self.__marker:
                raise
            return default
        else:
            del self[key]
            return value

    def popitem(self):
        '''D.popitem() -> (k, v), remove and return some (key, value) pair
           as a 2-tuple; but raise KeyError if D is empty.
        '''
        try:
            key = next(iter(self))
        except StopIteration:
            raise KeyError
        value = self[key]
        del self[key]
        return key, value

    def clear(self):
        'D.clear() -> None.  Remove all items from D.'
        try:
            while True:
                self.popitem()
        except KeyError:
            pass

    def update(*args, **kwds):
        ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
            If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
            If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
            In either case, this is followed by: for k, v in F.items(): D[k] = v
        '''
        if not args:
            raise TypeError("descriptor 'update' of 'MutableMapping' object "
                            "needs an argument")
        self, *args = args
        if len(args) > 1:
            raise TypeError('update expected at most 1 arguments, got %d' %
                            len(args))
        if args:
            other = args[0]
            if isinstance(other, Mapping):
                for key in other:
                    self[key] = other[key]
            elif hasattr(other, "keys"):
                for key in other.keys():
                    self[key] = other[key]
            else:
                for key, value in other:
                    self[key] = value
        for key, value in kwds.items():
            self[key] = value

    def setdefault(self, key, default=None):
        'D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D'
        try:
            return self[key]
        except KeyError:
            self[key] = default
        return default

MutableMapping.register(dict)

  

可以看到MutableMapping继承的是Mapping(不可变) ,最后把dict注册到MutableMapping.中   MutableMapping.register(dict)

可以通过 isinstance 查看一个字典的类型

from collections.abc import Mapping, MutableMapping
#dict属于mapping类型

a = {}
print (isinstance(a, MutableMapping))

测试结果如下

dict的常用方法

 

 copy(这里是浅拷贝)

a = {"biao1":{"company":"imooc"},
     "biao2": {"company": "imooc2"}
     }
#copy, 返回浅拷贝
new_dict = a.copy()
new_dict["bobby1"]["company"] = "imooc3"

调试结果如下 

 

fromkeys把可迭代的对象转变为dict

 

new_list = ["bobby1", "bobby2"]

new_dict = dict.fromkeys(new_list, {"company":"imooc"})

调试结果如下

get取值,可以设置一个默认值避免字典中keyerror异常

a = {"name1": "jack", "name2": "jane"}
value = a.get("name3", "not exist")

调试结果如下

 setdefault(),和get()相似,不同的是如果没有某个键名,会把此键名和默认值加入到字典中

a = {"name1": "jack", "name2": "jane"}

 
# 没有指定键名时
a.setdefault("name3", "not exist")

调试结果如下

update(), 可用于添加字典元素

 

a = {"name1": "jack", "name2": "jane"}

# 直接添加字典方式
a.update({"name3": "hong"})
# 使用参数名方式
a.update(name4="lilei", name5="mei")

调试结果如下

dict的子类

 如果我们想要继承dict重写我们的逻辑 ,不建议继承list和dict 因为他们是c语言写的,我们重写的函数有可能不会生效

#不建议继承list和dict
class Mydict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value*2)

my_dict = Mydict(one=1)  # 在这个时候没生效
print (my_dict)

my_dict["one"] = 1  # 在这个时候生效
print(my_dict)

打印结果

 

 应该使用python为我们提供的UserDict

from collections import UserDict

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

my_dict = Mydict(one=1)
pass

调试结果如下

 

dict 的子类defaultdict

 当我们取值一个不存在的值的时候,它会返回一个 {}

from collections import defaultdict

my_dict = defaultdict(dict)
my_value = my_dict["bobby"]

  

 调试结果如下

内部源码分析

 

set和frozenset

初始化一个set

# 使用set关键字
s1 = set('abc')
# 使用{}
s2 = {'a', 'b'}

print(type(s1), type(s2))

 

向set中添加元素

s1 = set('abc')
s1.add('d')
print(s1)  

  

使用update()函数更新set

s1 = set('abc')
s2 = set('xy')
s1.update(s2)
print(s1)

  

difference()函数来求两个集合的差集

s1 = set('abc')
s2 = set('cd')

# 相当于s1 - s2
re_set = s1.difference(s2)
print(re_set)

 

set的数学运算

s1 = set('abc')
s2 = set('cd')

# 差集
print(s1-s2)
# 交集
print(s1 & s2)
# 并集
print(s1 | s2)

 issubset()判断集合A是否为集合B的子集

s1 = set('abc')
s2 = set('c')

print(s2.issubset(s1))

  

dict和set的实现原理

list和dict的性能比较

  1 dict的查找性能远大于list
  2 在list中随着list数据量的增大,查找相同数据量的时间也会增大
  3 在dict中随着dict数据量的增大,查找相同数据量的时间不怎么受影响

 dict原理小结

dict找一个值之所以快,是因为他会根据这个键,进行哈希获得偏移量,直接取值,时间复杂度为0(1)

  1)dict的key或者set的值都必须是可hash的,他们的实现原理相同。不可变对象都是可hash的,比如string, tuple, fronzenset
  2)dict的内存花销大,但是查询速度快;自定义的类中,只要加上魔法函数__hash__, 那么这个类就是可hash的
  3)dict的存储顺序和元素添加顺序有关,因hash值冲突的原因
  4)添加数据的时候有可能会改变已有数据的顺序:存储dict的时候,python会预先申请一段大于dict数据需求的连续内存空间,以减少hash冲突的概率,当添加数据量使得大于分配内存空间的1/3的时候,python就会另申请一个较大的内存空间,把原先的数据进行迁移,重新进行hash值的计算

 

posted @ 2018-12-05 21:40  Crazymagic  阅读(531)  评论(0编辑  收藏  举报