zoukankan      html  css  js  c++  java
  • PythonI/O进阶学习笔记_5.python的set和dict

    前言:

    我一直觉得对我来说学习知识很忌讳不系统。本篇内容与上一篇 自定义序列类是有联系的。

    上一篇比较通范的了解了序列类的一些协议和特性,并且有些list的内容。这篇更加具体到set和dict这两个序列类。

    以此来了解python序列类的具体应用。(这篇比较简单)(感觉具体比抽象都更容易理解,但是也要学会思考把具体对象抽象化来表达,即提取共性)

    content:

    1.dict在abc中的序列类型和继承关系

    2.dict实现了的常用方法

    3.我可不可以继承dict这种序列类?

    4.set和frozenset

    5.set和dict的原理

    ==============

    1.dict在abc中的序列类型和继承关系

    dict在collection.abc中,实际上是属于MutableMapping(可变mapping)类型。

    跟上篇对可变序列类继承的分析一样,MutableMapping继承了Mapping的一些功能并且加了一些可变的特性,

    Mapping继承了Collection。接下来的继承和上篇的一样。

    2.dict实现了的常用方法

    如果用的是pycharm,还是用ctrl+b就能跳到python对dict的定义。

    常用:

    a = {"1":{"a":"aa"},
         "2":{"b":"bb"}}
    
    # 清空字典
    a.clear()
    
    # 浅拷贝字典 浅拷贝虽然可以正常赋值,但是如果 my_dopy_dict 中的值进行了改变,则 a 中的值也会进行对应的改变
    my_dopy_dict = a.copy()
    
    # 深拷贝 深拷贝则是实实在在的在内存当中声明了一个新的变量
    import copy
    new_dict = copy.deepcopy(a)
    
    # get函数 dict.get(要查找的key,如果没找到对应key的内容返回的数据)
    print(a.get("3",{1:"3"})) # {1: '3'}
    
    # dict.fromkeys() 函数用于创建一个新字典,以序列 seq 中元素做字典的键 seq可以是可迭代的,value 为字典所有键对应的初始值。
    my_list = [1, 2, 3]
    my_new_dict = dict.fromkeys(my_list, {"222":"3434"}) #{1: {'222': '3434'}, 2: {'222': '3434'}, 3: {'222': '3434'}}
    
    # setdefault() 函数和 get()方法 类似,
    # 如果键不存在于字典中,将会添加键并将值设为默认值。
    # 如果存在,则将会返回该key对应的value
    a.setdefault("3", "cc") # a= {'1': {'a': 'aa'}, '2': {'b': 'bb'}, '3': 'cc'}
    print(a.setdefault("2", "cc")) # 返回{'b': 'bb'}
    
    # update() 函数把字典dict2的键/值对更新到dict里。
    # 如果字典b中有与a相同的key,则会把a中的key对应的value进行更新
    # 如果字典b中有a中没有的key,则a会将未有的key与value添加进去
    b = {"3": "cc", "2": "dd"}
    a.update(b)
    print(a) # {'1': {'a': 'aa'}, '2': 'dd', '3': 'cc'}

    3.我可不可以继承dict这种序列类?(dict的子类)

    a.如果我偷懒想实现dict这种类型,能不能直接继承这种序列类呢?同理list是否可以?

    例:继承dict,并且重写设置dict key的value时调用的魔法函数,使其值变为2倍

    class Mydict(dict):
        def __setitem__(self, key, value):
            super().__setitem__(key, value*2)
    
    a=Mydict(b=1)
    print(a)
    
    a['b']=1
    print(a)

    输出:

    可以发现,原来同样功能和效果的,我们重写方法后,第一种方法去设置key的value值这一操作并没有调用我们重写的方法。

    所以并不建议去继承python的这种序列类。

    b.有没有什么办法我实在想继承?

    python里专门给了个UserDict类,可以实现想要的继承Dict类的效果

    from collections import UserDict
    class Mydict(UserDict):
        def __setitem__(self, key, value):
            super().__setitem__(key, value*2)
    
    mydict = Mydict(one = 1) # {'one': 2} 调用__setitem__这个魔法函数
    mydict["one"] = 2 # {'one': 4} 这种方式也可以调用__setitem__

    输出:

     c.python中Dcit实际也有子类实现:defaultdict

    使用:

    from collections import defaultdict # 这个是dict的子类
    mydict = defaultdict(dict)
    myvalue = mydict["bai"] # 如果不存在的话,返回{}

    输出:

    4.set和frozenset

    a.两者是啥有啥特点?

    set:集合(无序,不重复,可变)

    frozenset:不可变集合(无序,不重复,不可变)

    frozenset没有改变的方法 一旦初始化了 就不可变了。其中,不可变类型对可变类型的一个特点,不可变类型是可以作为dict的key的。
     
    b.set常用操作
    a=set('abcdee')
    a.add('f')
    print(a)
    another_set=set('defgh')
    #添加数据
    #a.update(another_set)
    #print(a)
    #集合的差集
    re_set=a.difference(another_set)
    #减法实现于__ior__魔法函数
    re_set2=a-another_set
    #集合的交集&
    re_set3=a&another_set
    #集合的并集|
    re_set4=a|another_set
    print(re_set)
    print(re_set2)
    print(re_set3)
    print(re_set4)
    #也可以用if in判断(实现于__contains__魔法函数)
    if 'a' in re_set:
        print('I am a set')

    5.set和dict的原理

    之前就提过,set的性能棒的。dict的查询性能远比起list要好。

    并且list中随着list数据的增大,查找时间会增大,而dict不会。

    这是为什么呢?

    因为dict使用hash这种数据结构存储。set也是。

    a.dict的散列表

    特点:

    - dict的key必须是可hash的,不可hash的是不能当成dict的key的,比如list
    - python申请内存的时候,会初始化一个小的连续的空空间
    - 由上一条可得这样 一定会存在浪费,这时候每次变动操作 会计算剩余空间,剩余空间小于1/3的时候,会重新生成空间并且将现在数据都拷贝过去(rehash)
    - 数组比这种链表结构好的地方,就是可以直接根据偏移量来存取,而不用全部开始从头遍历。
    (这种结构hash和重hash的策略用在很多地方,包括redis等)
     
    b.存储结构了解了,那么数据的查找过程呢?

    先计算a的散列值,查找表源是否为空,

    因为a是不变的,所以如果表源为空,那么就会抛出key error。

    如果表源不为空,也有可能是其他key,查看key是否是要查找的key。

    如果是其他key,重新散列循环查找。

    c.这种hash结构在python中的特点

    - 我们可以用__hash__这个魔法函数实现可hash对象

     - dict内存开销比较大,这是hash表的特点。

    - 实际上python内部类和对象,都是dict。

    - dict存储顺序和元素添加顺序有关。

    - 插入数据后检查剩余空间引发的重hash,会影响原来的数据(比如地址)。

  • 相关阅读:
    python 全局变量与局部变量
    Python 百分号字符串拼接
    Python集合的基本操作
    sorted by value in dict python
    gVim vundle
    vim config
    vim move the cursor in a long sentence
    步步为营-37-自动生成数据库连接字符串
    步步为营-36-ADO.Net简介
    步步为营-35-SQL语言基础
  • 原文地址:https://www.cnblogs.com/besttr/p/11531222.html
Copyright © 2011-2022 走看看