介绍

collections里面包含了很多除了内置类型之外的数据类型,我们使用它们有时可以很方便的完成一系列操作

ChainMap:搜索多个字典

  1. from collections import ChainMap
  2. '''
  3. ChainMap类一个字典序列,并按照其出现的顺序搜索以查找与键关联的值。
  4. ChainMap提供了一个很好的上下文容器,因为可以把它看做成一个栈,栈增长时发生变更,栈收缩时这些变更将被丢弃
  5. '''
  6. d1 = {"a": 12, "b": 22, "c": 33}
  7. d2 = {"b": 1, "c": 2, "d": 3}
  8. # 将多个字典传进去
  9. d = ChainMap(d1, d2)
  10. for k, v in d.items():
  11. print(k, v)
  12. '''
  13. b 22
  14. c 33
  15. d 3
  16. a 12
  17. '''
  18. # 可以看到打印的结果是无序的,而且如果多个字典中有相同的key,那么只保留第一次出现的key
  19. # 并且ChainMap有一个maps属性,存储了要搜索的映射列表。这个列表是可变的。所以可以直接增加新映射,或者改变元素的顺序以控制查找和更新行为。
  20. print(d.maps) # [{'a': 12, 'b': 22, 'c': 33}, {'b': 1, 'c': 2, 'd': 3}]
  21. # 这是我们存储的信息,如果在d.maps里面修改了,那么会怎么样呢?
  22. print(d1) # {'a': 12, 'b': 22, 'c': 33}
  23. d.maps[0]["a"] = "yoyoyo"
  24. # 可以看到d.maps里面存储的只是一个引用,因此改变之后会影响原来的结果
  25. print(d1) # {'a': 'yoyoyo', 'b': 22, 'c': 33}
  26. # 那我如果改变了原来的值,会不会影响d.maps呢?显然是可以的,毕竟同一个内存地址嘛
  27. d2["d"] = "我屮艸芔茻"
  28. print(d.maps) # [{'a': 'yoyoyo', 'b': 22, 'c': 33}, {'b': 1, 'c': 2, 'd': '我屮艸芔茻'}]

Counter:统计可散列的对象

  1. from collections import Counter
  2. '''
  3. Counter是一个容器,可以计算出序列中每一个元素出现的次数
  4. '''
  5. # 初始化
  6. print(Counter("aabbbc")) # Counter({'b': 3, 'a': 2, 'c': 1})
  7. print(Counter(['a', 'a', 'b', 'b', 'b', 'c'])) # Counter({'b': 3, 'a': 2, 'c': 1})
  8. print(Counter(a=2, b=3, c=1)) # Counter({'b': 3, 'a': 2, 'c': 1})
  9. c = Counter("aaabbc")
  10. # 表示a出现了三次,b出现了两次,c出现了一次
  11. print(c) # Counter({'a': 3, 'b': 2, 'c': 1})
  12. # 可以进行填充
  13. c.update("bcd")
  14. # 可以看到b和c的值都增加了1,并且出现了d
  15. print(c) # Counter({'a': 3, 'b': 3, 'c': 2, 'd': 1})
  16. # 访问计数,Counter对象可以像字典一样访问
  17. print(c["a"]) # 3
  18. # 如果访问一个不存在的key,不会引发KeyError,而是会返回0,表示对象中没有这个key
  19. print(c["mmp"]) # 0
  20. # 还可以使用elements进行迭代,会得到Counter对象中的所有元素
  21. print(list(c.elements())) # ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd']
  22. # 还可以计算出现最多的元素
  23. # 统计string中前三个出现次数最多的元素
  24. string = "sasaxzsdsadfscxzcasdscxzdfscxsasadszczxczxcsds"
  25. c = Counter(string)
  26. print(c) # Counter({'s': 13, 'c': 7, 'a': 6, 'x': 6, 'z': 6, 'd': 6, 'f': 2})
  27. print(c.most_common(3)) # [('s', 13), ('c', 7), ('a', 6)]
  28. # Counter还可以进行算数操作
  29. c1 = Counter("aabbccc")
  30. c2 = Counter("bbbccdd")
  31. print(c1) # Counter({'a': 2, 'b': 2, 'c': 3})
  32. print(c2) # Counter({'b': 3, 'c': 2, 'd': 2})
  33. # 如果c1的元素出现在了c2中,就把该元素减去,记住:减的是次数
  34. print(c1 - c2) # Counter({'a': 2, 'c': 1})
  35. '''
  36. a在c1中出现了2次,c2中没有出现,所有是a: 2。b在c1中出现两次,在c2中出现3次,所以一减就没有了。
  37. 而c在c1中出现了三次,在c2中出现两次,所以相减还剩下一次。至于c1没有的元素就不用管了
  38. '''
  39. # 相加就很好理解了
  40. print(c1 + c2) # Counter({'b': 5, 'c': 5, 'a': 2, 'd': 2})
  41. # 相交的话,查找公共的元素,并且取次数出现较小的那个
  42. print(c1 & c2) # Counter({'b': 2, 'c': 2})
  43. # 并集的话,取较大的,记住不是相加,所以b和c出现的次数不会增加,只是取较大的那个、
  44. print(c1 | c2) # Counter({'b': 3, 'c': 3, 'a': 2, 'd': 2})

defaultdict:缺少的键返回一个默认值

  1. from collections import defaultdict
  2. '''
  3. 标准字典中有setdefault和get,可以用来获取key对应的value。
  4. 如果key存在,两者会获取key对应的value
  5. 但如果key不存在,setdefault就会先将key和指定的默认值设置进去,然后返回一个默认值。
  6. 而get则只会返回默认值,。不会设置值
  7. example:
  8. d = {"a": 1}
  9. print(d.get("a", 0)) # 1
  10. print(d.setdefault("a", 0)) # 1
  11. print(d) # {"a": 1}
  12. print(d.get("b", 0)) # 0
  13. print(d) # {"a": 1}
  14. print(d.setdefault("b", 0)) # 0
  15. print(d) # {"a": 1, "b": 0}
  16. 所以这里相当于执行了两步操作。先将("b", 0)设置到字典里,然后再获取
  17. defaultdict在初始化的时候就会让调用者提前指定默认值
  18. '''
  19. # 统计每一个元素出现的次数
  20. s = "aabbccdddddee"
  21. d1 = {}
  22. for c in s:
  23. # 不存在就默认设置为0
  24. d1.setdefault(c, 0)
  25. d1[c] += 1
  26. print(d1) # {'a': 2, 'b': 2, 'c': 2, 'd': 5, 'e': 2}

如果使用defaultdict的话呢?

  1. from collections import defaultdict
  2. # 如果使用defaultdict的话呢?
  3. d2 = defaultdict(int)
  4. print(d2["a"]) # 0
  5. d2 = defaultdict(str)
  6. print("%r" % d2["a"]) # ''
  7. d2 = defaultdict(tuple)
  8. print(d2["a"]) # ()
  9. d2 = defaultdict(list)
  10. print(d2["a"]) # []
  11. # 如果获取不到key,那么会自动输出传入类型所对应的零值.能获取到key,输入key对应的value值
  1. from collections import defaultdict
  2. s = "aabbccdddddee"
  3. d2 = defaultdict(int)
  4. for c in s:
  5. '''
  6. 一开始没有值,设置为0,然后每来一个值就加上1
  7. '''
  8. d2[c] += 1
  9. print(d2) # defaultdict(<class 'int'>, {'a': 2, 'b': 2, 'c': 2, 'd': 5, 'e': 2})

此外还可以自定义返回值,只需要添加一个不需要参数的函数即可,并指定一个返回值

  1. from collections import defaultdict
  2. # 此时的默认值就是default
  3. d3 = defaultdict(lambda: "default")
  4. print(d3["aa"]) # default
  5. # 此外还可以添加参数,因为单独指定了aa,所以打印的时候以指定的为准
  6. # 如果没有指定,那么才会得到默认值
  7. d4 = defaultdict(lambda: "default", aa="bar")
  8. print(d4["aa"]) # bar
  9. print(d4["bb"]) # default

那么肯定会有人好奇,这是如何实现的呢?其实里面主要使用了一个叫做__missing__的魔法方法

  1. class MyDict(dict):
  2. def __getitem__(self, item):
  3. value = super().__getitem__(item)
  4. # 会执行父类的__getitem__方法,如果获取不到
  5. # 会检测我们是否定义__missing__方法,如果有,执行。没有,报错
  6. # 所以这里的value就是__missing__方法的返回值
  7. return value
  8. def __missing__(self, key):
  9. self[key] = "搞事情ヘ(´ー`ヘ)搞事情"
  10. return self[key]
  11. d = MyDict([("a", 3), ("b", 4)])
  12. print(d) # {'a': 3, 'b': 4}
  13. print(d["mmm"]) # 搞事情ヘ(´ー`ヘ)搞事情

deque:双端队列

双端队列支持从任意一端增加和删除元素。更为常用的两种数据结构(即栈和队列)就是双端队列的退化形式,它们的输入和输出被限制在某一端

  1. from collections import deque
  2. d = deque("abcdefg")
  3. print(d) # deque(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
  4. print(len(d)) # 7
  5. print(d[0]) # a
  6. print(d[-1]) # g
  7. # 由于deque是一种序列容器,因此同样支持list的操作。如:通过索引获取元素,查看长度,删除元素,反转元素等等
  8. # list支持的deque基本上都支持
  9. d.reverse()
  10. print(d) # deque(['g', 'f', 'e', 'd', 'c', 'b', 'a'])
  11. d.remove("c")
  12. print(d) # deque(['g', 'f', 'e', 'd', 'b', 'a'])

除了增删改查,并且还支持其他操作

  1. from collections import deque
  2. d = deque("abcdefg")
  3. # 填充元素
  4. # 首先可以像list一样添加元素,但是deque可以从两端添加
  5. d.append("yoyoyo") # 默认和list一样,在尾部添加
  6. d.appendleft("哟哟哟") # 也可以添加在头部
  7. print(d) # deque(['哟哟哟', 'g', 'f', 'e', 'd', 'b', 'a', 'yoyoyo'])
  8. # 还可以使用insert, 如果范围越界,自动添加在两端
  9. d.insert(100, "x")
  10. print(d) # deque(['哟哟哟', 'g', 'f', 'e', 'd', 'b', 'a', 'yoyoyo', 'x'])
  11. # extend,extendleft
  12. d1 = [1, 2, 3]
  13. d2 = deque([4, 5, 6])
  14. d.extend(d1)
  15. print(d) # deque(['哟哟哟', 'g', 'f', 'e', 'd', 'b', 'a', 'yoyoyo', 'x', 1, 2, 3])
  16. d.extendleft(d2)
  17. print(d) # deque([6, 5, 4, '哟哟哟', 'g', 'f', 'e', 'd', 'b', 'a', 'yoyoyo', 'x', 1, 2, 3])
  18. # 可以看到extend也支持从左端添加,而且不仅仅可以添加deque,任意序列类型都是可以的。
  19. d.extendleft("我屮艸芔茻")
  20. print(d) # deque(['茻', '芔', '艸', '屮', '我', 6, 5, 4, '哟哟哟', 'g', 'f', 'e', 'd', 'b', 'a', 'yoyoyo', 'x', 1, 2, 3])
  21. # 注意添加的顺序,我们是从左边开始添加的,先添加"我",然后"屮"跑到开头就把"我"挤到右边了,所以是结果是倒过来的
  22. # 那么如果消费deque里面的元素呢?
  23. print(d.pop()) # 3
  24. print(d.pop()) # 2
  25. print(d.pop()) # 1
  26. print(d.pop()) # x
  27. print(d.popleft()) # 茻
  28. # pop是从右端删除一个元素,popleft是从左端开始删除一个元素。但是如果我想pop掉指定的索引的元素,只能用pop函数,传入索引值即可
  29. # 注意:deque和queue一样,是线程安全的,是受GIL这把超级大锁保护的,可以不同的线程中进行消费。
  30. # 如果想清空里面的元素的话,可以像list、dict一样,使用clear函数
  31. d.clear()
  32. print(d) # deque([])
  33. # 旋转
  34. # deque还有一个很用的地方就是可以按任意一个方向进行旋转,从而跳过某些元素。
  35. # d.rotate(n)-->n大于0,从右边开始取n个元素放到左边,n小于0,从左边取n个元素放到右边
  36. d = deque(range(10))
  37. print(d) # deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
  38. d.rotate(2)
  39. # 从右边取2个元素放到左边,所以8和9被放到了左边
  40. print(d) # deque([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
  41. d.rotate(-3)
  42. # 从左边取3个元素放到右边,所以8、9、0被放到了右边
  43. print(d) # deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
  44. # 限制队列的大小
  45. # 我们在初始化一个双端队列的时候,还可以限制它的大小
  46. d = deque("abcdefg", maxlen=5)
  47. # 我们初始化7个元素,但是指定最大长度只有5,所以前面两个("a"和"b")就被挤出去了
  48. print(d) # deque(['c', 'd', 'e', 'f', 'g'], maxlen=5)
  49. d.appendleft("yoyoyo")
  50. # 当我往前面添加元素的时候,后面的就被挤出去了,因为队列最多只能容纳5个元素
  51. print(d) # deque(['yoyoyo', 'c', 'd', 'e', 'f'], maxlen=5)

namedtuple:带名字字段的元组子类

  1. from collections import namedtuple
  2. # 传入名字,和字段
  3. person = namedtuple("person", ["name", "age", "gender"])
  4. person1 = person(name="mashiro", age=16, gender="f")
  5. print(person1) # person(name='mashiro', age=16, gender='f')
  6. print(person1.name, person1.age, person1.gender) # mashiro 16 f
  7. print(person1[0]) # mashiro
  8. '''
  9. 可以看到不仅可以像普通的tuple一样使用索引访问,还可以使用像类一样通过.字段名访问
  10. '''
  11. person2 = person("satori", 16, "f")
  12. print(person2) # person(name='satori', age=16, gender='f')
  13. '''
  14. 注意:这个和普通的元组一样,是不可以修改的
  15. '''
  16. try:
  17. person2.name = "xxx"
  18. except AttributeError as e:
  19. print(e) # can't set attribute
  20. # 非法字段名,不能使用Python的关键字
  21. try:
  22. girl = namedtuple("女孩们", ["for", "in"])
  23. except ValueError as e:
  24. print(e) # Type names and field names cannot be a keyword: 'for'
  25. # 如果字段名重复了怎么办
  26. try:
  27. girl = namedtuple("女孩们", ["name", "age", "age"])
  28. except ValueError as e:
  29. print(e) # Encountered duplicate field name: 'age'
  30. # 如果非要加上重名字段呢,可以设置一个参数
  31. girl = namedtuple("女孩们", ["name", "age", "age"], rename=True)
  32. print(girl) # <class '__main__.女孩们'>
  33. girl1 = girl("koishi", 15, 15)
  34. # 可以看到重复的字段名会按照索引的值,在前面加上一个下划线。比如第二个age重复,它的索引是多少呢?是2,所以默认帮我们把字段名修改为_2
  35. print(girl1) # 女孩们(name='koishi', age=15, _2=15)
  36. # 此外我们所有的字段名都保存在_fields属性中
  37. print(girl1._fields) # ('name', 'age', '_2')

OrderDict:记住字典键值对的顺序

OrderDict是一个字典子类,可以记住字典中增加键的顺序。在Python2中,字典是无序的,但在Python3中,字典默认是有序的,所以这个个人觉得不是很常用,至少在python3中感觉不是很常用

  1. from collections import OrderedDict
  2. d = OrderedDict()
  3. d["a"] = "A"
  4. d["b"] = "B"
  5. d["c"] = "C"
  6. for k, v in d.items():
  7. print(k, v)
  8. '''
  9. a A
  10. b B
  11. c C
  12. '''
  13. # 此外也可以在初始化的时候,添加元素
  14. print(OrderedDict({"a": 1})) # OrderedDict([('a', 1)])
  15. # 相等性,对于常规字典来说,只要里面元素一样便是相等的,不考虑顺序。但是对于OrderDict来说,除了元素,顺序也要一样,否则就不相等
  16. d1 = {"a": 1, "b": 2}
  17. d2 = {"b": 2, "a": 1}
  18. print(d1 == d2) # True
  19. d1 = OrderedDict({"a": 1, "b": 2})
  20. d2 = OrderedDict({"b": 2, "a": 1})
  21. print(d1 == d2) # False
  22. # 重排
  23. # 在OrderDict中可以使用move_to_end()将键移至序列的起始位置或末尾位置来改变键的顺序
  24. d3 = OrderedDict({"a": 1, "b": 2, "c": 3, "d": 4})
  25. d3.move_to_end("c") # 表示将key="c"的这个键值对移动到末尾
  26. print(d3) # OrderedDict([('a', 1), ('b', 2), ('d', 4), ('c', 3)])
  27. d3.move_to_end("c", last=False) # 表示将key="c"的这个键值对移动到行首
  28. print(d3) # OrderedDict([('c', 3), ('a', 1), ('b', 2), ('d', 4)])

collections:内建模块,提供额外的集合类的更多相关文章

  1. python常用内建模块 collections,bs64,struct,hashlib,itertools,contextlib,xml

    #  2  collections 是Python内建的一个集合模块,提供了许多有用的集合类. # 2.1 namedtuple #tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成: p ...

  2. Python内建模块--collections

    python内建模块--collections collections是Python内建的一个集合模块,提供了许多有用的集合类. namedtuple 我们知道tuple可以表示不变集合,例如,一个点 ...

  3. Python常用的内建模块

    PS:Python之所以自称“batteries included”,就是因为内置了许多非常有用的模块,无需额外安装和配置,即可直接使用.下面就来看看一些常用的内建模块. 参考原文 廖雪峰常用的内建模 ...

  4. Python常用内建模块

    Python常用内建模块 datetime 处理日期和时间的标准库. 注意到datetime是模块,datetime模块还包含一个datetime类,通过from datetime import da ...

  5. python的常用内建模块与常用第三方模块

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 一.常用内置模块1.datetimePython 提供了一个 time 和 calendar 模块可 ...

  6. Python常用内建模块和第三方库

    目录 内建模块 1  datetime模块(处理日期和时间的标准库) datetime与timestamp转换 str与datetime转换 datetime时间加减,使用timedelta这个类 转 ...

  7. Python3 内建模块 hashlib、itertools、HTMLParser、urllib

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制 ...

  8. 四十六 常用内建模块 itertools

    Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数. 首先,我们看看itertools提供的几个“无限”迭代器: >>> import itertools ...

  9. Python的程序结构[5] -> 模块/Module[0] -> 内建模块 builtins

    builtins 内建模块 / builtins Module 在Python的模块中,有一种特殊模块,无需导入便可以使用,其中包含了许多内建函数与类. builtins 模块内容 / builtin ...

  10. Python3 内建模块 datetime/collections/base64/struct

    datetime 我们先看如何获取当前日期和时间: >>> from datetime import datetime >>> now = datetime.now ...

随机推荐

  1. syspolicy_purge_history作业故障排除

    描述 我们有一台数据库服务器windows 2012 r2 上有安装sql server 2012 和sql server 2016双实例,后续又把sql 2016的服务全部停用,即只保留sql 20 ...

  2. Linux下十大命令行下载工具

    Wget 这是最有名的工具,可用于通过CLI下载.这款工具功能很丰富,可以充当某种功能完备的GUI下载管理器,它拥有一款理想的下载管理器所需要的所有功能,比如它可以恢复下载,可以下载多个文件,出现某个 ...

  3. 静态web页面与动态web页面的区别

    一.静态web页面 在静态web程序中,客户端使用web浏览器经过网络连接到服务器上,使用HTTP协议发起一个请求(Request),告诉服务区我现在需要得到哪个页面,所有的请求交给web服务器,之后 ...

  4. Windows Server 2019 配置远程桌面授权服务器许可RD

    Windows Server 2019 配置远程桌面授权服务器许可RD Windows Server 201默认的最大远程登录连接为2个,超过这个数目需要使用license server进行授权,但又 ...

  5. 【VS开发】CSplitterWnd的定制使用

    一.基本的CSplitterWnd的使用 1. 在CMainFrame中添加一个CSplitterWnd成员: CSplitterWnd m_splitterwnd1; 2. 基于CView创建两个新 ...

  6. prometheus 监控 jar应用服务 + 修改监听IP和端口

    1.修改服务的启动脚本 [root@do1cloud01 init.d]# vim learn-school nohup ${JAVA_HOME}/bin/java -javaagent:/usr/l ...

  7. spring-boot war包部署(二)

    环境 jdk 8 tomcat 8.5 sts 4.4.2 maven 3.6.1 背景 有时候,服务器已经有了,我们必须要使用 war 包进行部署,所以需要 spring boot 支持打包和部署成 ...

  8. Linux系列(3):入门之正确的关机方法

    前言:在Windows(非NT主机系统)系统中,由于是单人假多任务的情况,所以即使你计算机关机,对于别人也没有丝毫影响!不过,在Linux下面,由于每个程序(或者服务)都是在在背景下执行,因此,在看不 ...

  9. Zero Array---思维题

    链接        submit B. Zero Array time limit per test 1 second memory limit per test 256 megabytes inpu ...

  10. winform中使用TextBox滚动显示日志信息

    代码如下: private void ShowInfo(string msg) { this.BeginInvoke((Action)(() => { textBox1.AppendText(s ...