Python中的collections模块(三) 命名元组namedtuple和双端队列deque

本文介绍了Python内置collections模块中的namedtuple用于创建带命名字段的元组,提高代码易读性,以及deque的高效插入和删除功能,特别关注其在大数据场景下的性能对比.

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

Python 内置模块collections, 目标是提供各种专门的集合数据类型来解决特定的编程问题。

本系列介绍其中的数据结构特点和使用方法,  以便遇到某些特定的问题,可以找到对应的数据来处理, 达到事半功倍的效果

⭐namedtuple用于创建其子类的工厂函数tuple,提供命名字段,允许按名称访问项目,同时保持按索引访问项目的能力
⭐deque一个类似序列的集合,支持从序列的任一端有效地添加和删除项目
OrderedDict根据插入键的时间保持键值对排序的字典子类
ChainMap一个类似字典的类,允许将多个映射视为单个字典对象
defaultdict一个字典子类,用于为缺失的键构建默认值并自动将它们添加到字典中
Counter一个字典子类,支持方便地对序列或可迭代中的唯一项进行计数

本文介绍其中两个 namedtuple,  deque​​​​​​​, 其他的可以参考

Python中的collections模块(一) 使用Counter,pythonic的对象计数方式

Python中的collections模块(二) 有序字典OrderedDict和链接字典ChainMap

Python中的collections模块(四) UserString,UserList,和UserDict​​​​​​​

1. 使用namedtuple提高代码可读性

tuple(元组)是python内置的数据结构,是一种不可变的有序数据集合.通过坐标索引来访问数据

In [1]: card = ('Spades', '7')

In [2]: card[0]
Out[2]: 'Spades'

使用namedtuple可以创建命名字段的tuple。可以使用点表示法和字段名称访问给定命名元组中的值,如obj.attr. 使用方式:namedtuple(typename:str, field_names:list or tuple)

In [3]: from collections import namedtuple

In [4]: Card = namedtuple('Cards', ['suit', 'rank'])

In [5]: spade_7 = Card('spades', '7')
In [6]: spade_7
Out[6]: Cards(suit='spades', rank='7')

In [7]: spade_7.suit
Out[7]: 'spades'
In [8]: spade_7.rank
Out[8]: '7'

# 同样支持坐标索引
In [9]: spade_7[0]
Out[9]: 'spades'

如以上例子所示,使用namedtuple创建的卡牌对象,可读性明显高于原始的tuple,通过属性和值,spade_7这张牌的花色是黑桃,值是7.

2. 高效插入和删除的双端队列-deque

使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。deque除了支持和list同样功能的append和extend,还支持左端插入appendleft,extendleft。以及左侧弹出popleft

from collections import deque

In [1]: dq = deque([1,2,3])

In [2]: dq
Out[2]: deque([1, 2, 3])

In [3]: dq.extend([4,5,6])
In [4]: dq.appendleft(-1)
In [5]: dq
Out[5]: deque([-1, 1, 2, 3, 4, 5, 6])

In [6]: dq.popleft()
Out[6]: -1

2.1 maxlen和rotate

deque 可以指定maxlen来设置队列深度,超出深度的数据会被丢弃

In [7]: dq = deque([1,2,3,4,5,6],maxlen=4)

In [8]: dq
Out[8]: deque([3, 4, 5, 6])

In [9]: dq.append(7)
In [10]: dq
Out[10]: deque([4, 5, 6, 7])

In [11]: dq.appendleft(0)
In [12]: dq
Out[12]: deque([0, 4, 5, 6])

# 使用rotate,将数据向后滚动, n可以指定滚动的距离
In [13]: dq.rotate()
In [14]: dq
Out[14]: deque([5, 6, 0, 4])

In [15]: dq.rotate(2)
In [16]: dq
Out[16]: deque([4, 5, 6, 0])

2.2 使用deque实现栈和队列

class Stack:
    def __init__(self, data, depth):
        self.stack = deque(data, maxlen=depth)

    def push(self, v):
        self.stack.append(v)

    def pop(self):
        self.stack.pop()
class Queue:
    def __init__(self, data, depth):
        self.stack = deque(data, maxlen=depth)

    def push(self, v):
        self.stack.appendleft(v)

    def pop(self):
        self.stack.pop()

2.3 queue和list的性能对比

测试脚本

from time import perf_counter
from collections import deque

n = 100000

start = perf_counter()
lst = []
for i in range(10): 
    lst.extend(range(n))
    now = perf_counter()
    print(f'extend {i} :', now - start)
    start = now

start = perf_counter()
dq = deque()
for i in range(10): 
    dq.extend(range(n))
    now = perf_counter()
    print(f'extend {i} :', now - start)
    start = now
次数n=10万n=100万n=1000万
listdequelistdequelistdeque
10.000160.000240.012670.01990.1350.18206
20.000990.002060.018680.019640.152350.18039
30.000430.002940.02080.01980.170420.18593
40.000400.002980.025120.019140.210750.19321
50.000370.00320.022680.019020.21910.18765
60.000300.002040.02456        0.019330.251370.21404
70.000480.002090.024640.019870.294510.18301
80.000460.002450.025770.021120.261840.17619
90.000330.002310.013280.019970.127870.179
100.000580.002830.031140.02040.329560.18637

从图中可以看出,随着数据的增大,list的extend的时间逐渐增大, deque的extend的时间相对平稳。当数据达到1000万级时,deque的性能优势才明显强于list。日常工作中少量的数据时,二者性能差距不大。

3.总结

① namedtuple 可以像访问对象的属性一样获取元组中的数据,提高代码的可读性。

② deque 提供左端的插入和弹出,100万级别的数据对比list的性能提升并不明显. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值