python容器类型

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

容器总览

主要涉及包

  • 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. 更多详细参考

python数据类型之列表

可变集合set和不可变集合frozenset

1. UML关系图

2. 更多详细参考

python数据类型之集合

元组tuple和字符串str

1. UML关系图

2. 更多详细参考

python数据类型之元组

python数据类型之字符串

字典dict

1. UML关系图

2. 更多详细参考

python数据类型之字典

高级容器

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必备开发工具

img

三、Python视频合集

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

img

四、实战案例

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

img

五、Python练习题

检查学习结果。

img

六、面试资料

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

img

最后祝大家天天进步!!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值