4种非常实用的python内置数据结构


Posted in Python onApril 28, 2021

array

Python不仅仅可以使用内置的list实现数组,还支持像C语言那样的指定类型的原生数组array。
很显然,因为list可以存储各种类型的对象,而array只存储一个指定的原生类型,所以当数据量较大时,原生array在内存占用方面要比list小。
而且array不像C语言里那样在定义时就限制了大小,它支持list所支持的各种常用函数。相比之下Python的array更像是C++的vector。

from array import array
l = list(range(100))
a = array.fromlist(l)

print(l.__sizeof__(), a.__sizeof__())

目前array有两个限制。首先,它只支持整数、小数、unicode字符,而不能像C++的vector那样支持多种数据类型。另外目前指定类型比较麻烦,我们需要使用类型对应的字母缩写来指定,而不能使用简单的诸如int,float的方式。

a = array('i')
a.append(1)
a.append(4)
Type code  C Type Python Type Minimum size in bytes
'b' signed char int 1
'B'  unsigned char int 1
'u' wchar_t  Unicode character 2
'h'  signed short int 2
'H'  unsigned short int 2
'i' signed int int 2
'I'  unsigned int int 2
'l' signed long int 4
'L'  unsigned long int 4

更详细的信息可以参考:https://docs.python.org/3.8/library/array.html

defaultdict

C++的map对于新的key会自动使用value type的默认构造函数构造一个值,而Python默认的dict对于不存在的key的访问会抛出异常(赋值除外)。这是因为Python不知道value的类型,所以没办法为我们默认构造。
defaultdict要求我们在构造时指定一个类型,然后会自动根据需要初始化value。这样我们就可以使用简单的代码来实现很多功能。

下面的代码,我对比了使用defaultdict和original dict实现将学生按照姓的首字母分组的功能,以及分类计数的功能。

import collections
students = ['Zhang San', 'Li Si', 'Zhou liu', 'Chen qi', 'Cheng ba']
# using defaultdict
dd = collections.defaultdict(list)
for s in students:
	key = s[0]
	dd[key].append(s)
print(dd)
# using original dict (method 1)
od = {}
for s in students:
	key = s[0]
	if key not in do:
		od[key] = []
	od[key].append(s)
print(od)

scores = ['A', 'B', 'C', 'A', 'A', 'B', 'C', 'B', 'A', 'A']
# using defaultdict
dd = collections.defaultdict(int)
for s in scores :
	dd[s] += 1
print(dd)
# using original dict (method 2)
od = collections.defaultdict(int)
for s in scores :
	if s not in do:
		do[s] = 1
	else:
		do[s] += 1
print(od)

Named Tuple

编程实践中我们经常需要创建一些小的数据结构用来整合一组相关联的数据,简单的比如地理坐标的经纬度,颜色的RGB值或者矩形框的左上和右下坐标,复杂的比如构造一个窗口的一组参数。
实践中,我们通常有3中实现方法:

  • 对每一个这样的数据结构创建一个class。优点是可以直接使用名字访问数据成员,而且支持复杂的访问逻辑和数据操作。缺点是需要编写对应的类和必须的函数,管理文件和引用关系。
  • 使用tuple。优点是编写简单,内存使用效率高。缺点是只能使用下标访问,可读性差,容易出错。
  • 使用dict,用str来作为对于属性的名字。优点是编写相对简单,而且保留了变量的名字。缺点是需要使用字符串表示名字较为麻烦,而且每一个结构都要保存作为名字的字符串,浪费空间。

collections的nametuple可以为我们直接构造一个具有名字的简单类型,方便快捷地实现类似手写了一个class的效果。
需要注意的是collections.nametuple是一个factory function,它用来帮我们创建一个类型,而不是这个类型的具体对象。创建类型时,我们可以指定各个属性的名字,之后就可以使用.来访问了,而且它同时还支持使用下标访问。同时Named Tuple还支持_asdict函数用来将内部的数值转换成一个dict。

# class
class Rect:
	def __init__(self, x1, y1, x2, y2):
		self.x1 = x1
		self.y1 = y1
		self.x2 = x2
		self.y2 = y2
		
def area_class(r):
	w = r.x2 - r.x1
	h = r.y2 - r.y1
	return w*h

r1 = Rect(1,3,5,5)
# <__main__.Rect object at 0x7fde252a87f0>
# to show its content, we need to implement __repr__(self) or __str__(self)
print(area_class(r1))

# tuple
def area_tuple(r):
	w = r[2]-r[0]
	h = r[3]-r[1]
	return w*h

r2 = (1,3,5,5)
print(r2)
# (1, 3, 5, 5)
print(area_tuple(r2))

# dict
def area_dict(r):
	w = r["x2"] - r["x1"]
	h = r["y2"] - r["y1"]
	return w*h

r3 = {"x1":1, "y1":3, "x2":5, "y2":5}
print(r3)
# {'x1': 1, 'y1': 3, 'x2': 5, 'y2': 5}
print(area_tuple(r3))

# named tuple
import collections
Rectangle = collections.namedtuple("Rectangle", ["x1", "y1", "x2", "y2"])

def area_namedtuple(r):
	w = r.x2 - r.x1
	y = r.y2 - r.y1
	return w*h

r4 = Rectangle(1,3,5,5)
print(r4)
# Rectangle(x1=1, y1=3, x2=5, y2=5)
x1,y2,x2,y2 = r4
print(x1,y2,x2,y2)
# 1 3 5 5
print(area_namedtuple(r4))
print(area_class(r4)) # work with "." grammar
print(area_tuple(r4)) # work with index
print(area_dict(r4._asdict())) # work with dict

Counter

顾名思义,Counter是用来对元素进行计数的,它也是collections这个包里的。根据Python的官方文档,它是dict类型的一个子类。
在构造的时候输入一个iterable的类型,比如list,range或是一个mapping的类型,比如dict,defaultdict。然后Counter就会对其中的元素进行计数。
比较特殊的是,Counter对负数没有做特殊处理,就是说在特殊操作下允许出现测试为负,后面我们会有例子。

c = Counter()                           # a new, empty counter
c = Counter('gallahad')                 # a new counter from an iterable
print(c)
# Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
print(c)
# Counter({'red': 4, 'blue': 2})
c = Counter(cats=4, dogs=8)             # a new counter from keyword args
print(c)
# Counter({'dogs': 8, 'cats': 4})

除了基本的计数功能,它还支持一些常用的相关功能。比如:

  • 按照频率排序(most_common([n]))。其中n是可选输入,表示返回前n个最频繁的元素和他们的频率。默认情况下返回所有的元素。
  • 按照频率输出元素本身(elements())。它会返回元素本身,但是元素的顺序不是原来的,相同的元素会连续输出。不同元素之间,按照他们的出现顺序输出,这一点是OrderedDict以及3.7之后的dict所提供的特性。
  • 两个Counter相减(substract(c))。它可以从第一个counter上减去第二个counter中对应元素出现的次数。对于只出现在第二个coutner中元素,默认其在第一个counter中出现0次。
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
# ['a', 'a', 'a', 'a', 'b', 'b']
Counter('abracadabra').most_common(3)
# [('a', 5), ('b', 2), ('r', 2)]

c1 = Counter(a=4, b=2, d=-2)
c2 = Counter(a=1, b=2, c=3, d=4)
c1.subtract(c2)
c1
# Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

更多的参考信息大家可以参考官方文档:

https://docs.python.org/3/library/collections.html

以上就是4种非常实用的python内置数据结构的详细内容,更多关于python内置数据结构的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python基础教程之元组操作使用详解
Mar 25 Python
详解TensorFlow在windows上安装与简单示例
Mar 05 Python
python中pip的安装与使用教程
Aug 10 Python
python简单操作excle的方法
Sep 12 Python
python自带tkinter库实现棋盘覆盖图形界面
Jul 17 Python
python爬虫-模拟微博登录功能
Sep 12 Python
Python Opencv提取图片中某种颜色组成的图形的方法
Sep 19 Python
Python 使用type来定义类的实现
Nov 19 Python
Python+Kepler.gl轻松制作酷炫路径动画的实现示例
Jun 02 Python
python学习将数据写入文件并保存方法
Jun 07 Python
基于注解实现 SpringBoot 接口防刷的方法
Mar 02 Python
python 提取html文本的方法
May 20 Python
Python基础详解之描述符
Apr 28 #Python
详解Python 3.10 中的新功能和变化
Apr 28 #Python
Python基础之数据结构详解
Apr 28 #Python
Python基础详解之邮件处理
python实现黄金分割法的示例代码
Apr 28 #Python
Python 流媒体播放器的实现(基于VLC)
tensorflow+k-means聚类简单实现猫狗图像分类的方法
You might like
PHP 的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
2012/12/07 PHP
php一些错误处理的方法与技巧总结
2013/08/10 PHP
递归删除一个节点以及该节点下的所有节点示例
2014/03/19 PHP
php实现倒计时效果
2015/12/19 PHP
WordPress特定文章对搜索引擎隐藏或只允许搜索引擎查看
2015/12/31 PHP
理解Javascript_14_函数形式参数与arguments
2010/10/20 Javascript
js判断数据类型如判断是否为数组是否为字符串等等
2014/01/15 Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
2015/03/03 Javascript
基于jQuery Bar Indicator 插件实现进度条展示效果
2015/09/30 Javascript
jquery获取复选框的值的简单实例
2016/05/26 Javascript
微信小程序实战之自定义抽屉菜单(7)
2017/04/18 Javascript
addEventListener()与removeEventListener()解析
2017/04/20 Javascript
详解webpack 配合babel 将es6转成es5 超简单实例
2017/05/02 Javascript
微信小程序开发之animation循环动画实现的让云朵飘效果
2017/07/14 Javascript
JS同步、异步、延迟加载的方法
2018/05/05 Javascript
微信小程序之swiper滑动面板用法示例
2018/12/04 Javascript
Node使用Nodemailer发送邮件的方法实现
2020/02/24 Javascript
Vue作用域插槽实现方法及作用详解
2020/07/08 Javascript
在vue中使用vant TreeSelect分类选择组件操作
2020/11/02 Javascript
[03:48]大碗DOTA
2019/07/25 DOTA
Python读取视频的两种方法(imageio和cv2)
2018/04/15 Python
Python人脸识别第三方库face_recognition接口说明文档
2019/05/03 Python
tensorflow入门:tfrecord 和tf.data.TFRecordDataset的使用
2020/01/20 Python
python 元组的使用方法
2020/06/09 Python
python推导式的使用方法实例
2021/02/28 Python
阿拉伯时尚购物网站:Nisnass
2021/02/07 全球购物
JS原生实现轮播图的几种方法
2021/03/23 Javascript
外贸业务员求职自荐信分享
2013/09/21 职场文书
应届生文秘专业个人自荐信格式
2013/09/21 职场文书
大学毕业后的十年规划
2014/01/07 职场文书
三分钟演讲稿事例
2014/03/03 职场文书
珍惜时间演讲稿
2014/05/14 职场文书
婚内房产协议书范本
2014/10/02 职场文书
酒店财务经理岗位职责
2015/04/08 职场文书
百年校庆宣传标语口号
2015/12/26 职场文书
Spring Boot 整合 Apache Dubbo的示例代码
2021/07/04 Java/Android