容器总览

主要涉及包
- collections.abc 抽象基类包
- collections 容器扩展包
层次划分
- 抽象基类
- 内置容器类型
- 扩展容器类型
抽象基类
可迭代基类
class collections.abc.Iterable
- 为所有子类提供__iter__()方法
_class_collections.abc.AsyncIterable
- 为所有子类提供__aiter__()方法
容器基类
class collections.abc.Container
- 为所有子类提供__contains__()方法
可调用基类
class collections.abc.Callable
- 为所有子类提供__call__()方法
可哈希基类
class collections.abc.Hashable
- 为所有子类提供__hash__()方法
计算长度基类
class collections.abc.Sized
- 为所有子类提供__len__()方法
其它基类
class collections.abc.Buffer
- 为所有子类提供__buffer__()方法
_class_collections.abc.Awaitable
- 所有子类必须实现__await__()方法
内置容器
列表list和数组array
1. UML关系图

2. 更多详细参考
可变集合set和不可变集合frozenset
1. UML关系图

2. 更多详细参考
元组tuple和字符串str
1. UML关系图

2. 更多详细参考
字典dict
1. UML关系图

2. 更多详细参考
高级容器
UserString
1. 特点
- UserString是一个类
- 是对str的包装
- 拥有str对象的所有方法,包括特殊方法
- 通过对子类添加新的方法或特殊方法实现新的功能
2. 用法
- 通过调用属性data获取数据
- 子类添加__setitem__方法将不可变字符串str变成可变
- 通过继承UserString自定义新的String字符串类型
from collections import UserString
str1 = 'hello'
# MyString类通过继承 UserString 类并添加新的特殊方法 __setitem__ 实现类似列表的操作
class MyString(UserString):
def __setitem__(self, index, value):
self.data = self.data.replace(self.data[index], value)
ustr1 = MyString('hello')
print(str1, str1[0], ustr1, ustr1[0], ustr1.data) # hello h hello h hello
# str1[0] = 'x' # TypeError: 'str' object does not support item assignment
ustr1[0] = 'x'
print(str1, str1[0], ustr1, ustr1[0], ustr1.data) # hello h xello x xello
UserList
1. 特点
- UserList是一个类
- 是对list的包装
- 拥有list对象的所有属性和方法,包括特殊方法
- 通过对子类添加新的方法或特殊方法实现新的功能
2. 用法
- 通过调用属性data获取数据
- 通过继承UserList自定义新的list列表类型
from collections import UserList
class MyList(UserList):
pass
ulist = MyList([i for i in range(10)])
print(ulist, ulist.data) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ulist.extend([item for item in 'hello'])
print(ulist) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'h', 'e', 'l', 'l', 'o']
UserDict
1. 特点
- UserDict是一个类
- 是对dict的包装
- 拥有dict对象的所有属性和方法,包括特殊方法
- 通过对子类添加新的方法或特殊方法实现新的功能
2. 用法
- 通过调用属性data获取数据
- 通过继承UserDict自定义新的dict字典类型
from collections import UserDict
class MyDict(UserDict):
pass
udict = MyDict(name ='张三', age ='李四')
print(udict) # {'name': '张三', 'age': '李四'}
deque
1. 特点
- Deque 队列是双端队列对象
- Deque 队列是对栈或队列的泛化(该名称的发音为 “deck”,是 “double-ended queue” 的简写形式)。
- Deque 支持线程安全,高度节省内存地从 deque 的任一端添加和弹出条目,在两个方向上的大致性能均为_O_(1);在执行相同操作时,比list更加节省内存
- 对于快速随机访问,使用列表list效率更高
2. 定义
_class_collections.deque([iterable[,maxlen]])
- iterable(迭代对象) ,如果iterable没有指定,新队列为空
- maxlen 指定队列的最大长度。如果_maxlen_没有指定或者是
None,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filtertail的功能。它们同样可以用与追踪最近的交换和其他数据池活动
3. deque对象支持的方法
- append(x) 添加 x 到右端。
- appendleft(x) 添加 x 到左端。
- clear() 移除所有元素,使其长度为0.
- copy() 创建一份浅拷贝。
- count(x) 计算 deque 中元素等于 x 的个数。
- extend(iterable) 扩展deque的右侧,通过添加iterable参数中的元素。
- extendleft(iterable) 扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。
- index(x[,start[,stop]]) 返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发
[ValueError](https://link.zhihu.com/?target=https%3A//docs.python.org/zh-cn/3/library/exceptions.html%23ValueError)。 - insert(i,x) 在位置 i 插入 x 。如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个
[IndexError](https://link.zhihu.com/?target=https%3A//docs.python.org/zh-cn/3/library/exceptions.html%23IndexError)。 - pop() 移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个
[IndexError](https://link.zhihu.com/?target=https%3A//docs.python.org/zh-cn/3/library/exceptions.html%23IndexError)。 - popleft() 移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发
[IndexError](https://link.zhihu.com/?target=https%3A//docs.python.org/zh-cn/3/library/exceptions.html%23IndexError)。 - remove(value) 移除找到的第一个 value。 如果没有的话就引发
[ValueError](https://link.zhihu.com/?target=https%3A//docs.python.org/zh-cn/3/library/exceptions.html%23ValueError)。 - reverse() 将deque逆序排列。返回
None。 - rotate(n=1) 向右循环移动 n 步。 如果 n 是负数,就向左循环。如果deque不是空的,向右循环移动一步就等价于
d.appendleft(d.pop()), 向左循环一步就等价于d.append(d.popleft())。
from collections import deque
# 创建队列
d = deque('ghi')
for elem in d:
print(elem.upper(), sep=',', end= '')
d.append('j')
d.appendleft('f')
print(d) # deque(['f', 'g', 'h', 'i', 'j'])
# 除去队列中最右侧的项并返回该项
print(d.pop()) # 'j'
# 除去队列中最左侧的项并返回该项
print(d.popleft()) # 'f'
print(list(d)) # ['g', 'h', 'i']
print(d[0]) # 'g'
print(d[-1]) # 'i'
print(list(reversed(d))) # ['i', 'h', 'g']
print('h' in d) # True
# 一次向队列中添加多个元素
d.extend('jkl')
print(d) # deque(['g', 'h', 'i', 'j', 'k', 'l'])
# 向右翻转1项
print(d.rotate(1)) # deque(['l', 'g', 'h', 'i', 'j', 'k'])
# 向左翻转1项
print(d.rotate(-1)) # deque(['g', 'h', 'i', 'j', 'k', 'l'])
print(deque(reversed(d))) # deque(['l', 'k', 'j', 'i', 'h', 'g'])
d.clear()
# 空队列无法执行pop
# d.pop()
'''
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel- d.pop()
IndexError: pop from an empty deque
'''
# 倒序输入的队列
d.extendleft('abc')
print(d) # deque(['c', 'b', 'a'])
4. deque的应用
- 限长deque提供了类似Unixtail过滤功能
def tail(filename, n=10):
'Return the last n lines of a file'
with open(filename) as f:
return deque(f, n)
- 维护一个近期添加元素的序列,通过从右边添加和从左边弹出
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# https://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
- 轮询调度器
'''
一个轮询调度器可以通过在deque中放入迭代器来实现。值从当前迭代器的位置0被取出并暂存(yield)。
如果这个迭代器消耗完毕,就用popleft()将其从对列中移去;否则,就通过rotate()将它移到队列的末尾
'''
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Remove an exhausted iterator.
iterators.popleft()
OrderedDict
1. 特点
- 是对dict的包装
- 实现有序的字典
- 被设计用来处理频繁操作的数据,因此常应用在缓存LRU算法,弊端是性能差些
2. 用法
popitem方法
-
从字典中去除第一项(当参数last=True,可以实现LIFO栈顺序的效果)或最后一项(当参数last=False,可以实现FIFO队列顺序的效果),返回对应项的键值对
-
对比pop
-
pop: 传入指定key返回对应的value, key不存在则抛出keyError异常
-
popitem: 返回第一或最后项(key, value)
-
效果都是去除字典中的指定key的项
move_to_end方法
- 从字典中移动指定的项(参数key)到开始(当参数last=False)或结束位置(当参数last=True),如果key不存在则抛出keyError异常
缓存操作
# popitem 方法
odict = OrderedDict(name ='张三', age =24, grade ='二年级') # 等价于 OrderedDict({'name': '张三', 'age': 24, 'grade': '二年级'})
print(odict) # OrderedDict({'name': '张三', 'age': 24, 'grade': '二年级'})
odict_last_item = odict.popitem(last=True) # 去除字典中最后一项
odict_first_item = odict.popitem(last=False) # 去除字典中第一项
print(odict_last_item, odict_first_item, odict) # ('grade', '二年级') ('name', '张三') OrderedDict({'age': 24})
odict = OrderedDict(name ='张三', age =24, grade ='二年级')
value = odict.pop('age')
print(value, odict) # 24 OrderedDict({'name': '张三', 'grade': '二年级'})
# move_to_end 方法
odict = OrderedDict(name ='张三', age =24, grade ='二年级')
print(f"移动前的值为:{odict}") # 移动前的值为:OrderedDict({'name': '张三', 'age': 24, 'grade': '二年级'})
try:
odict.move_to_end('age') # 默认移动到最后
print(f"移动后的值为:{odict}") # 移动后的值为:OrderedDict({'name': '张三', 'grade': '二年级', 'age': 24})
except KeyError as e:
print(f'当前处理的key值{e}不存在')
d = OrderedDict.fromkeys('abcde')
print(d, type(d)) # OrderedDict({'a': None, 'b': None, 'c': None, 'd': None, 'e': None}) <class 'collections.OrderedDict'>
d.move_to_end('b')
print(''.join(d)) # 'acdeb'
d.move_to_end('b', last=False)
print(''.join(d)) #'bacde'
# 缓存操作
class LastUpdatedOrderedDict(OrderedDict):
'新增的项放到字典最后'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
odict = LastUpdatedOrderedDict(name ='张三', age =24, grade ='二年级')
odict['height'] = 165
print(odict) # LastUpdatedOrderedDict({'name': '张三', 'age': 24, 'grade': '二年级', 'height': 165})
# functools.cache应用:减少递归调用次数
import functools
@functools.cache
def factorial(n):
return n * factorial(n-1) if n else 1
defaultdict
1. 特点
- 是dict的子类
- 支持dict的所有操作
2. 定义
class collections.defaultdict(default_factory=None,/[,…])
3. 用法
from collections import defaultdict
# 分组合并
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1), ('red', 1), ('red', 3), ('blue', 4)]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
print(sorted(d.items())) # [('blue', [2, 4, 4]), ('red', [1, 1, 3]), ('yellow', [1, 3])]
d = {}
for k, v in s:
d.setdefault(k, []).append(v)
print(sorted(d.items())) # [('blue', [2, 4, 4]), ('red', [1, 1, 3]), ('yellow', [1, 3])]
# 分组统计
s = 'mississippi'
d = defaultdict(int)
for k in s:
d[k] += 1
print(sorted(d.items())) # [('i', 4), ('m', 1), ('p', 2), ('s', 4)]
# 分组合并去重
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1), ('red', 1), ('red', 3), ('blue', 4)]
d = defaultdict(set)
for k, v in s:
d[k].add(v)
print(sorted(d.items())) # [('blue', {2, 4}), ('red', {1, 3}), ('yellow', {1, 3})]
d = {}
for k, v in s:
d.setdefault(k, set()).add(v)
print(sorted(d.items())) # [('blue', {2, 4}), ('red', {1, 3}), ('yellow', {1, 3})]
# 嵌套字典
dict_nest = defaultdict(dict)
dict_nest['grade1']['name'] = '张三'
dict_nest['grade1']['age'] = 20
dict_nest['grade2']['name'] = '李四'
dict_nest['grade2']['age'] = 30
print(dict(dict_nest.items())) # {'grade1': {'name': '张三', 'age': 20}, 'grade2': {'name': '李四', 'age': 30}}
dict1 = {'name': '张三', 'age': 24, 'grade': '二年级', 'height': 165}
dedict = defaultdict(name = '张三', age = 24, grade = '二年级', height = 165)
print(dict1['name'], dedict['name']) # 张三 张三
Counter
1. 特点
- 是dict的子类
- 支持dict的所有操作
- 用于计数hashable对象。它是一个多项集,元素存储为字典的键而它们的计数存储为字典的值。
2. 定义
class collections.Counter([iterable-or-mapping])
3. 用法
from collections import Counter
# 统计字符串中元素
c = Counter('abcdeabcdabcaba')
# 元素中三个计数最多的
print(c.most_common(3)) # [('a', 5), ('b', 4), ('c', 3)]
# 列出所有不重复的元素
print(sorted(c)) # ['a', 'b', 'c', 'd', 'e']
# 列出排序后的字符串
print(''.join(sorted(c.elements()))) # 'aaaaabbbbcccdde'
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements()) # ['a', 'a', 'a', 'a', 'b', 'b']
# 统计所有元素和
print(sum(c.values())) # 15
# 获取字符串中字母a的计数
print(c['a']) # 5
for elem in 'shazam':
c[elem] += 1
c['a'] # 7
del c['b']
c['b'] # 0
d = Counter('simsalabim')
c.update(d)
c['a'] # 9
c.clear()
c # Counter()
c = Counter('aaabbc')
c['b'] -= 2
c.most_common() # [('a', 3), ('c', 1), ('b', 0)]
ChainMap
1. 特点
-
ChainMap类(就称为链映射类),是个类似字典(dict)的类,用于快速链接许多个映射,将多个映射对象组合成一个单一的可更新的视图, 以便将它们作为单个单元处理。它通常比创建一个新字典并运行多个update()调用要快得多
-
不会合并传入的映射。相反,它们被保存在内部映射列表中。
-
ChainMap中可包含不同key值的重复键。
-
按顺序在内部映射列表搜索键,当在搜索整个映射列表后缺少键时抛出KeyErrror;通过get方式获取时,搜索不到则返回None
-
更新删除操作时只改变内部列表中的第一个映射。
-
支持字典dict所有常用方法。除此自外,ChainMap特有的:
-
属性maps: 获取对应的包含所有映射的可更新的list列表。
-
方法new_child: 创建一个新的ChainMap对象,如果传入参数则新的映射会出现在第一项;如果不传则等价于原来的;
-
属性parents:返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射
2. 定义
-
class ChainMap(_collections_abc.MutableMapping)
-
参数: 可以指定一个字典类型的数据,如果不指定默认为一个空字典
from collections import ChainMap
dict1 = {'name': '张三', 'age': 24}
dict2 = {'name': '李四', 'grade': '二年级', 'height': 165}
# 构建 ChainMap 对象
dict_group = ChainMap(dict1, dict2)
print(dict_group) # ChainMap({'name': '张三', 'age': 24}, {'name': '李四', 'grade': '二年级', 'height': 165})
print(list(dict_group.keys()), list(dict_group.values())) # ['name', 'grade', 'height', 'age'] ['张三', '二年级', 165, 24]
# 获取指定key的值
try:
# name = dict_group['name1']
name = dict_group['name']
print(name) # 张三
except KeyError as e:
print(f'不存在这样的key: {e}')
print(dict_group.get('name'), dict_group.get('name1')) # 张三 None
dict_group.update(name='王五')
print(dict_group) # ChainMap({'name': '王五', 'age': 24}, {'name': '李四', 'grade': '二年级', 'height': 165})
print(dict_group.maps) # [{'name': '王五', 'age': 24}, {'name': '李四', 'grade': '二年级', 'height': 165}]
print(dict_group.parents.maps) # [{'name': '李四', 'grade': '二年级', 'height': 165}]
dict3 = {'ss': '李四', 'dd': '二年级'}
new_dict_group = dict_group.new_child(dict3)
print(new_dict_group.maps) # [{'ss': '李四', 'dd': '二年级'}, {'name': '王五', 'age': 24}, {'name': '李四', 'grade': '二年级', 'height': 165}]
# 实际应用1:将多个库合并成一个
from collections import ChainMap
# 水果价格
fruits_prices = {"apple": 0.80, "grape": 0.40, "orange": 0.50}
# 蔬菜价格
veggies_prices = {"tomato": 1.20, "pepper": 1.30, "onion": 1.25}
# 总价格合并
prices = ChainMap(fruits_prices, veggies_prices)
# 购买的商品及数量
order = {"apple": 4, "tomato": 8, "orange": 4}
# 计算总金额
for product, units in order.items():
price = prices[product]
subtotal = units * price
print(f"{product:6}: ${price:.2f} × {units} = ${subtotal:.2f}")
# 输出结果
''''apple : $0.80 × 4 = $3.20
tomato: $1.20 × 8 = $9.60 orange: $0.50 × 4 = $2.00'''
'''
namedtuple
1、特点
- 是一个函数
- 返回值是元组tuple的子类
2、和NamedTuple以及dataclass的区别
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
print(Point.__doc__) #'Point(x, y)'
# 使用位置参数实例化
p = Point(11, y=22)
# 类似元组可索引
print(p[0] + p[1]) # 33
# 像常规元组一样解包
x, y = p
print(x, y) #(11, 22)
print(p.x + p.y) # 33
# 转换成字典
d = p._asdict()
print(d['x']) # 11
# 将字典转换成Point类
p = Point(**d)
print(p) # Point(x=11, y=22)
# 修改类对象中的属性值
print(p._replace(x=100)) # Point(x=100, y=22)
#
t = [44, 55]
p = Point._make(t)
print(p) # Point(x=44, y=55)
# 获取类对象字段属性名
print(p._fields) # ('x', 'y')
# 使用getattr获取属性值
print(getattr(p, 'x')) # 44
# 应用:关联数据与对象
'''
employees.csv文件内容如下:
张三,22,后端工程师,研发部,C-1
李四,33,前端工程师,产品部,C-3
'''
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "r", encoding='UTF-8'))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
以上就是“python容器类型”的全部内容,希望对你有所帮助。
关于Python技术储备
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、Python必备开发工具

三、Python视频合集
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

四、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

五、Python练习题
检查学习结果。

六、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

最后祝大家天天进步!!
上面这份完整版的Python全套学习资料已经上传至CSDN官方,朋友如果需要可以直接微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】。

本文围绕Python容器类型展开,介绍了涉及的collections.abc抽象基类包和collections容器扩展包。详细阐述了抽象基类、内置容器(如列表、集合等)和高级容器(如UserString、deque等)的特点、用法及相关方法,还提供了Python学习资料。

738

被折叠的 条评论
为什么被折叠?



