找回密码
 会员注册
查看: 20|回复: 0

Python高级特性深入NamedTuple命名元组

[复制链接]

4

主题

0

回帖

13

积分

新手上路

积分
13
发表于 2024-9-10 06:09:14 | 显示全部楼层 |阅读模式
介绍和元组tuple一样,NamedTuple也是不可变数据类型,创建之后就不能改变内容。如其名,和tuple的区别在于“Named”,即"命名"。NamedTuple不像数组那样使用下标读写,反而和类相似,使用.来读写。基本语法创建NamedTuple的函数定义collections.namedtuple(typename,field_names,*,rename=False,defaults=None,module=None)1参数说明:typename:新创建的类的名称。field_names:字段名称列表。必须是有效的Python变量名称,且不能以下划线开头。rename:是否自动转换无效字段名。defaults:字段默认值列表。module:__module__的值。使用教程创建首先看看如何创建命名元组。以Point(代表二维坐标中的一个点)为例:#导包fromcollectionsimportnamedtuple#创建普通元组point=(22,33)print(point)#输出:(22,33)#创建命名元组Point=namedtuple('Point','xy')point_A=Point(22,33)print(point_A)#输出:Point(x=22,y=33)1234567891011重点是这两句话Point=namedtuple('Point','xy')point_A=Point(22,33)12需要注意,namedtuple()是用来创建类的,不是创建对象实例!我们先用namedtuple创建了一个名为Point,有两个字段x、y的子类,然后将这个类赋给Point变量。然后Point(22,33)就是普通的new的语法。类似于如下代码:classPoint: def__init__(self,x,y): self.x=x self.y=ypoint_A=Point(22,33)12345创建命名元组对象时,也可以使用位置参数a=Point(1,2)b=Point(y=2,x=1)a==b#>>>True123field_names参数用来设置命名元组字段名,有三种风格可以选择。下面几种都是等价写法:Point=namedtuple('Point','xy')Point=namedtuple('Point','x,y')Point=namedtuple('Point',['x','y'])#下面都是合法代码#中间允许存在任意空白字符Point=namedtuple('Point','x,\t\t\t\n\ny')Point=namedtuple('Point','x\t\t\t\n\ny')#元组也可以Point=namedtuple('Point',('x','y'))#事实上只要是可迭代都行deffields(): yield'x' yield'y'Point=namedtuple('Point',fields())12345678910111213141516使用命名元组首先是一个元组,元组能怎么用,命名元组当然也可以。print(point_A[0])print(point_A[1])print(*point_A)#tupleunpack#输出"""22332233"""12345678910然后是命名元组的特殊用法:print(point_A.x)print(point_A.y)#输出"""2233"""12345678常用方法namedtuple创建的类还附赠了一些实用方法:Point._make(iterable)#从某个序列创建命名元组point._asdict()#转成字典point._replace(**kargs)#返回一个新元组,新元组里的指定字段被替换为指定值point._fields#列出字段名point._field_defaults#列出字段默认值123456设置默认值可以为命名元组的字段设置默认值,只需要在创建类的时候传入defaults参数即可。#四维向量#默认值为Vector4D(0,0,0,0)Vector4=namedtuple('Vector4D','xyzw',defaults=(0,0,0,0))v1=Vector4()v2=Vector4(1)v3=Vector4(1,2,w=4)print(v1)print(v2)print(v3)#输出"""Vector4D(x=0,y=0,z=0,w=0)Vector4D(x=1,y=0,z=0,w=0)Vector4D(x=1,y=2,z=0,w=4)"""1234567891011121314151617默认值的数量可以小于字段数,表示为右边n个参数设置默认值。Foo=namedtuple('Foo','abcd',defaults=(1,2))print(Foo(22,33))print(Foo())#输出"""Foo(a=22,b=33,c=1,d=2)Traceback(mostrecentcalllast):File"D:\TempCodeFiles\named_tuple.py",line6,inprint(Foo())TypeError:Foo.__new__()missing2requiredpositionalarguments:'a'and'b'"""123456789101112更好的表示方式namedtuple()的写法既不直观,也不优雅。Python3.5新增了一种更好的写法:#>=Python3.5fromtypingimportNamedTupleclassPointA(NamedTuple): x:int=0 y:int=0#>=Python2fromcollectionsimportnamedtuplePointB=namedtuple('PointB','xy',defaults=(0,0))print(PointA(2,3)==PointB(2,3))#输出:True1234567891011继承并扩展NamedTuplenamedtuple()返回的是一个正常的类。既然它是一个类,当然也可以被继承。创建一个Point命名元组,增加一个方法,求两点距离。#>=Python3.5classPoint(NamedTuple): x:int=0 y:int=0 defdistance(self,p)->float: returnmath.sqrt((self.x-p.x)**2+(self.y-p.y)**2)#>=Python2classPoint(namedtuple('Point','xy',defaults=(0,0))): defdistance(self,p)->float: returnmath.sqrt((self.x-p.x)**2+(self.y-p.y)**2)a=Point()b=Point(3,2)print(a,b)print(a.distance(b))1234567891011121314151617应用读csv文件以读入一个储存英语单词的csv文件为例。importcsvfromcollectionsimportnamedtuple#定义命名元组#按照csv列名来定义字段Word=namedtuple('Word','word,type,chs_def,eng_ch,context,example')file_path=r'C:\Users\ZhouXiaokang\Desktop\单词Vol1Ch1Ep2.csv'withopen(file_path,'r',encoding='utf-8')asf: reader=csv.reader(f) next(reader)#跳过行 forwordinmap(Word._make,reader): print(f'{word.word}{word.type}.{word.chs_def}|例:{word.context}')12345678910111213输出chirpn&v.(鸟、昆虫)啾啾叫,发唧唧声|例:(*chirp**chirp**chirp*)screechv.(车辆、汽车轮胎)发出刺耳声|例:(*screech*)Shirokoterm.白子|例:mugv.对…行凶抢劫|例:Youdidn'tgetmugged,didyou?faintv.晕厥;晕倒|例:What'sthat?Youfaintedfromhunger?......123456作为字典的代替品表示数据相对于字典的优势:1.快、小2..field比['field']更清晰以下源码摘自baidupcs_py库:classPcsFile(NamedTuple):"""ABaiduPCSfilepath:str#remoteabsolutepathis_dir:Optional[bool]=Noneis_file:Optional[bool]=Nonefs_id:Optional[int]=None#fileidsize:Optional[int]=Nonemd5:Optional[str]=Noneblock_list:Optional[List[str]]=None#blockmd5listcategory:Optional[int]=Noneuser_id:Optional[int]=Nonectime:Optional[int]=None#servercreatedtimemtime:Optional[int]=None#servermodifedtimelocal_ctime:Optional[int]=None#localcreatedtimelocal_mtime:Optional[int]=None#localmodifedtimeserver_ctime:Optional[int]=None#servercreatedtimeserver_mtime:Optional[int]=None#servermodifedtimeshared:Optional[bool]=None#thisfileissharedifTrue"""path:str#remoteabsolutepathis_dir:Optional[bool]=Noneis_file:Optional[bool]=Nonefs_id:Optional[int]=None#fileidsize:Optional[int]=Nonemd5:Optional[str]=Noneblock_list:Optional[List[str]]=None#blockmd5listcategory:Optional[int]=Noneuser_id:Optional[int]=Nonectime:Optional[int]=None#servercreatedtimemtime:Optional[int]=None#servermodifedtimelocal_ctime:Optional[int]=None#localcreatedtimelocal_mtime:Optional[int]=None#localmodifedtimeserver_ctime:Optional[int]=None#servercreatedtimeserver_mtime:Optional[int]=None#servermodifedtimeshared:Optional[bool]=None#thisfileissharedifTruerapid_upload_info:Optional[PcsRapidUploadInfo]=Nonedl_link:Optional[str]=None@staticmethoddeffrom_(info)->"PcsFile":returnPcsFile(path=info.get("path"),is_dir=info.get("isdir")==1,is_file=info.get("isdir")==0,fs_id=info.get("fs_id"),size=info.get("size"),md5=info.get("md5"),block_list=info.get("block_list"),category=info.get("category"),user_id=info.get("user_id"),ctime=info.get("ctime"),mtime=info.get("mtime"),local_ctime=info.get("local_ctime"),local_mtime=info.get("local_mtime"),server_ctime=info.get("server_ctime"),server_mtime=info.get("server_mtime"),shared=info.get("shared"),)1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162源码见Github。关键部分在这里:#Build-uptheclassnamespacedictionary#andusetype()tobuildtheresultclass#收集类的方法、字段等class_namespace={'__doc__':f'{typename}({arg_list})','__slots__'),'_fields':field_names,'_field_defaults':field_defaults,'__new__':__new__,'_make':_make,'__replace__':_replace,'_replace':_replace,'__repr__':__repr__,'_asdict':_asdict,'__getnewargs__':__getnewargs__,'__match_args__':field_names,}forindex,nameinenumerate(field_names):doc=_sys.intern(f'Aliasforfieldnumber{index}')class_namespace[name]=_tuplegetter(index,doc)#创建新类result=type(typename,(tuple,),class_namespace)1234567891011121314151617181920212223type()函数传入一个参数,用来获取对象的类;如果传入三个参数,就变成了动态创建类,相当于class的动态写法。classFoo:defhello(self):print('Hello')#等价于defhello(self):print('Hello')Foo=type('Foo',(object,),{'hello':hello})1234567参考文章https://docs.python.org/zh-cn/3/library/collections.html#collections.namedtuplehttps://realpython.com/python-namedtuple/
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-7 06:54 , Processed in 0.642592 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表