Python中的set和dict学习笔记

1、map类型

dict就是一种map类型。先看个例子

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

# print(isinstance(dict,MutableMapping)) # False 因为isinstance判断的是实例的类型

补充:字典类型a实际上并不是去继承MutableMapping类,而是实现了MutableMapping类中的一些方法(魔法函数),源码中最后通过MutableMapping.register(dict)语句实现,即注册之后就可以判断dictMutableMapping类型

具体来说

from abc import ABCMeta, abstractmethod
import sys

__all__ = ["Awaitable", "Coroutine",
           "AsyncIterable", "AsyncIterator", "AsyncGenerator",
           "Hashable", "Iterable", "Iterator", "Generator", "Reversible",
           "Sized", "Container", "Callable", "Collection",
           "Set", "MutableSet",
           "Mapping", "MutableMapping",
           "MappingView", "KeysView", "ItemsView", "ValuesView",
           "Sequence", "MutableSequence",
           "ByteString",
           ]

在源码的抽象基类collections中的abc模块,可以看到有Mapping类型和MutableMapping类型(可修改),而dict就是属于MutableMapping

MutableMapping类中定义了很多方法,如__setitem____delitem__pop等等,MutableMapping类继承的正是Mapping类。

listdict有很多操作方法是一样的,这是因为它们都继承了Collection类。

2、dict中的常用方法(只说几个蛮重要的)
  • clear方法 (清空字典)
a = {"bobby1":{"company":"imooc"},
     "bobby2": {"company": "imooc2"}
     }
a.clear() 
print(a) # {}
  • copy方法(浅拷贝和深拷贝)

什么是浅拷贝,看如下例子。

a = {"bobby1": {"company": "im"},
     "bobby2": {"company": "im2"}
     }
print(a)

new_dict = a.copy()
new_dict["bobby1"]["company"] = "im3"
print(new_dict)

print(a)

# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}

将字典a拷贝到new_dict之后,因为a中的bobby1指向的也是一个字典{'company': 'im'},这个字典不会再拷贝了,所以修改new_dict之后,bobby1指向的还是那个字典,只不过这个字典内容已经修改了。所以再打印出来的字典a发生了变化。这就是浅拷贝的机制。

深拷贝就需要用到python中的copy。请看如下示例:

import copy

a = {"bobby1": {"company": "im"},
     "bobby2": {"company": "im2"}
     }
print(a)

new_dict = copy.deepcopy(a)
new_dict["bobby1"]["company"] = "im3"
print(new_dict)
print(a)

# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}

可以看到修改复制得到的的new_dicta并没有受到影响。

  • 静态方法fromkeys(接收任意iterable对象)

直接看例子

new_list = ["bobby1", "bobby2"]
new_dict = dict.fromkeys(new_list, {"company": "im"})
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}

将列表中的元素作为keys,value自己添加。

  • get方法

第一个参数要得到的键keys,第二个参数默认的是在字典里如果没有要找的keys,则返回指定的输出。

# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
value = new_dict.get("bobby", {"jj"})
print(value) # {"jj"}
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
value = new_dict.get("bobby1")
print(value)
# {'company': 'im'}
  • item方法

来看一个例子

# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
for key, value in new_dict.items():
    print(key, value)
# bobby1 {'company': 'im'}
# bobby2 {'company': 'im'}
  • setfeault方法

源码

  def setdefault(self, *args, **kwargs): # real signature unknown
        """
        Insert key with a value of default if key is not in the dictionary.
        
        Return the value for key if key is in the dictionary, else default.
        """
        pass

看例子(其实就是添加键值对)

# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
defult = new_dict.setdefault("bobby", "im2")
print(defult)
print(new_dict)

# im2
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im2'}
  • update方法

源码

  def update(self, E=None, **F): # known special case of dict.update
        """
        D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
        If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
        If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
        In either case, this is followed by: for k in F:  D[k] = F[k]
        """
        pass

来看一个例子

# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}

new_dict.update({"bobby": "im2"})
print(new_dict)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im2'}

当然也可以传任意的iterable对象。

new_dict.update(bobby = "im4",bobby4="im5")
# new_dict.update([("bobby" , "im4"),("bobby4","im5")]) #列表也可以
# new_dict.update((("bobby" , "im4"),("bobby4","im5"))) #元组也可以
print(new_dict)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im4', 'bobby4': 'im5'}
3、dict的子类(UserDict和Defaultdict)
  • 不建议继承ListDict

举个栗子

定义一个Mydict类,让它继承dict类,然后覆盖(重写)dict类中的__setitem__方法,让它去调用dict父类的__setitem__方法,变成2倍value

class Mydict(dict):
    def __setitem__(self,key,value):
        super().__setitem__(key,value*2)
        
my_dict = Mydict(one=1)
print(my_dict) # {'one':1}

实例化后输出是{'one':1},发现并没有调用__setitem__魔法函数。

但是如果我们使用my_dict["one"]=1这种方法,就发现会去调用__setitem__方法,结果变为{'one':2}。

所以说某些情况下,c语言实现的dict(内置类型)不会去调用覆盖的方法,如果实在想要继承可使用collection模块中的UserDict。也就是去继承UserDict

from collections import UserDict
class Mydict(UserDict):
    def __setitem__(self,key,value):
        super().__setitem__(key,value*2)
        
my_dict = Mydict(one=1)
print(my_dict) # {'one':2}
  • defaultdict

前言

源码的UserDict类中有一个__missing__方法(如下面的代码),而在我们的dict中可以重写__missing__方法。

这个方法是在我们找不到某个key时被调用,逻辑大概就是判断key是否在data中,在的话直接返回data里面的值,不在的话,就会去判断这个class中有没有__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__方法,从该方法中的if self.default_factory is None: raise KeyError((key,))self[key] = value = self.default_factory()语句看出,如果当某个键值找不到的时候,就会将该值设置进来,也就是去调用default_factory()

    def __missing__(self, key): # real signature unknown; restored from __doc__
        """
        __missing__(key) # Called by __getitem__ for missing key; pseudo-code:
          if self.default_factory is None: raise KeyError((key,))
          self[key] = value = self.default_factory()
          return value
        """
        pass

default_factory实际上就是一个属性,设置一个值,将值赋到key上(self[key] = value = self.default_factory()

 default_factory = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """Factory for default value called by __missing__()."""

举个栗子

from collections import defaultdict
my_dict = defaultdict(dict) # 若为int 返回0;若为list 返回[]
my_value = my_dict["bobby"]
print(my_value)
# {} 

setdefaultdefaultdict也可以参照这篇不错的文章来理解——文章地址

4、set和frozenset

set 集合 fronzenset 不可变集合

无序, 不重复

  • set
# b = set(['a', 'b', 'c', 'd', 'e'])
# print(b) # {'e', 'b', 'd', 'c', 'a'} 每次结果不一样,无序
s = set('abcdee')
# {'a', 'b', 'd', 'e', 'c'}

一种初始化方法

set={'a','b'}
print(type(set)) # <class 'set'>
  • fronezset
s = {'a', 'b'}
s.add('c')
print(s) #{'b','a','c'}
s = frozenset("abcde")  
print(s) # frozenset({'e', 'c', 'd', 'a', 'b'})
# s.add('b') # AttributeError: 'frozenset' object has no attribute 'add'

注意: 不可变类型frozenset 可以作为字典的key

  • 向set添加数据
s = {'a', 'b'}
print(s)

another_set = set("cef")
s.update(another_set)
print(s)

# {'b', 'a'}
# {'b', 'e', 'f', 'a', 'c'}
  • difference 差集
s = {'a', 'b', 'c'}
print(s)

another_set = set("cef")
re_set = s.difference(another_set) # re_set = s - another_set 这样也是一样的效果,s中有,anot中没有
print(re_set)
# {'a', 'b'}
  • 查找集合中的元素(in)
if 'c' in re_set:
	print('yes')

补充:只要对象实现了__contains__魔法函数,就可以使用in

  • 判断是否为子集
print(s.issubset(re_set)) #True
5、补充知识
dict查找的性能远远大于list
在dict中查找元素不会随着dict的增大而增大
dict的key或者set的值都必须是可以hash的,不可变对象都是可hash的,比如str,fronzenset,tuple等或者自己实现的类 `__hash__`
dict的内存花销大,但是查询速度快,自定义的对象或者python内部的对象都是用dict包装的
dict的存储顺序和元素添加顺序有关
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值