Python编程基础:序列类型概述(python序列类型及运算)
off999 2024-11-17 00:33 36 浏览 0 评论
关注公众号:用Python学机器学习,获取更多更新。
序列首先是一种数据存储方式,用来存储一系列的数据。序列存储数据的主要特点就是数据在内存空间中是连续存储的,例如字符串abc(字符串属于序列),其在内存中的存储可以表达如下:
基于这一存储特点,Python中实现了序列类型。序列类型与很多Python内置数据类型都有密切的关系,掌握好序列类型将对理解Python内置数据类型有很大的帮助,这篇文章我们对序列类型做一个简要介绍。
序列类型的分类
Python中有很多数据类型都可以称为是序列类型,例如字符串str、列表list、元祖tuple、字节对象bytes、数组array.array、内存视图memoryview、字节数组bytearray等等。序列有很多分类标准,根据序列中存储的是值还是引用,序列可以分为扁平序列和容器序列。根据序列是否可以被修改,可以分为不可变序列(Sequence)和可变序列(MutableSequence)。
扁平序列
扁平序列有两个特点,第一,内部存储的都是值而不是引用(或者说是内存地址);第二,内部存储的都是同一种数据类型,而且只能存储数值、字节、字符这样的基础数据类型。常见的扁平序列如字符串str、字节bytes、数组array.array、字节数组bytearray和内存视图memoryview等。
我们举一个例子,例如a = 'abc',这是一个创建字符序列str的命令。这条命令运行时,Python解释器会先在内存中开辟一块连续的内存空间来存储a、b和c三个字符,创建好对象后会将这块内存的首地址抛给外界,由变量a来接收,变量a是另一块内存,这块内存中就存储了字符串序列'abc'的内存首地址。之后如果需要使用'abc'这个对象,都是通过变量a。当解释器读到变量a时,发现其存储的是一个内存地址,就会直接读取这个内存地址对应数据,完成对象的访问。如下图所示:
容器序列
与扁平序列相对应,容器序列中存储的不是值而是对象的引用,正因为如此,容器中可以容纳任何数据类型。常见的容器序列包括列表list、元祖tuple等。
如下例子:a = [1,'a',[5.6,'n']],这是一个列表,其在内存中存储方式如下图所示:
可以看到,对于列表本身来说,其在内存中是连续的,但是列表的内存中存储的并不是值本身,而是对象(列表中元素)的引用。至于对象(列表中的元素)本身,则存储在别的内存块中,这些内存可能是连续的,也可能是不连续的,大概率是不连续的。而且,列表中不仅仅可以存储基本数据类型int、str,还可以存储列表list。
可变序列
可变序列是指可以在原内存地址上对数据进行修改的序列。这类序列包括列表list、字节数组bytearray、数组array.array,内存视图memoryview等。
列表list提供了append方法,可以在原列表内存地址上对列表进行修改:
>>> b = [1,2,3] >>> id(b) 1665411984704 >>> b.append(6) >>> id(b) 1665412212544 >>> b [1,2,3,6]
这里给列表增加了一个元素,但是列表的内存地址并没有发生变化。
不可变序列
不可变序列指的是不可以在原内存地址上对序列进行修改。这类序列包括字符序列str、元祖tuple、和字节序列bytes。
例如,对于字符序列str,一旦创建就无法在原内存地址上对数据进行修改,强行修改则是创建新的对象:
>>> a = '123' >>> id(a) 1665411984752 >>> a = 'anc' >>> id(a) 1665411959088
可能有人对元祖不可修改无法理解,对于容器序列来说,不可变指的是容器中每一个元素的引用不可变,而不是每一个元素的值不可变。如下面的例子:
>>> a = ('1','2',['3','4'])
# 记录元祖的内存地址
>>> id(a)
1665412226688
# 记录元祖中第一个元素的内存地址
>>> id(a[0])
140710344787616
# 修改元祖中的第一个元素,可以看到报错了,提示元祖对象不支持赋值。因为第一个元素是一个不可变对象,强行修改会创建新的对象,产生新的引用,而元祖不支持修改内部元素的引用,所以报错。
>>> a[0]='5'
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
a[0]='5'
TypeError: 'tuple' object does not support item assignment
# 记录元祖中第三个元素列表的内存地址
>>> id(a[2])
1665412212544
# 我们的元祖中第三个元素是一个list,这是一个可变的序列,使用append方法会在原内存地址上进行修改,这样保证元素中第三个元素的引用并不会发生变化,所以修改成功。
>>> a[2].append('9')
# 可以看到第三个元素列表修改成功
>>> a
(1, 2, [3, 4, 9])
# 但是第三个元素的内存地址并未发生变化
>>> id(a[2])
1665412212544
# 元祖第三个元素修改后,元祖本身的内存地址并未发生变化。
>>> id(a)
1665412226688这个例子中,我们先创建了一个元祖(1,2,[3,4]),元祖中有三个元素1、2、[3,4],前两个都是不可变的字符序列str,通过前面的例子我们已经知道,如果对字符序列强行修改,不会改变原来的字符,而是创建新的对象。新的对象就意味着产生一个新的内存地址,这会导致元祖第一个元素的引用发生变化。这是元祖不能够接受的,所以出现报错。
然而,我们发现对创建的元祖的第三个元素进行修改,却修改成功了,原因是第三个元素是一个列表list,是一个可变序列,对其调用append方法是在原地址上对数据进行的修改,而并不会改变本身的内存地址,因此元祖第三个元素的引用不会发生变化,故而修改成功。
因此我们说对于容器序列,不可变意味着元素的引用不可变,相反,可变则意味着引用可以发生变化:
>>> a = [1,2,[3,4]] >>> id(a) 2338191916032 >>> id(a[2]) 2338200822784 >>> a[2]=5 >>> a [1, 2, 5] >>> id(a[2]) 140710407702304 >>> id(a) 2338191916032
看见列表是可以修改元素的引用的,因为它是可变类型。
序列类型的协议
以上我们对Python中的序列类型进行了分类,接下来我们学习一下序列类型的协议。通过这一部分的学习,你会对面向对象以及常见序列类型有更加深刻的认识。
Python为可变序列和不可变序列提供了两个基类Sequence和MutableSequence,这两个基类存在于内置模块collections.abc中,与其他常见的类如int、list等不同,这两个基类都是抽象基类。这里涉及到一个新的概念抽象基类,什么是抽象基类呢?
对于抽象基类,目前可以不用关注太多,只需知道抽象基类是指不能实例化产生实例对象的类,后面我们会专用一篇文章来介绍抽象基类。
Sequence和MutableSequence是两个抽象基类,如果不能实例化产生实例对象,那你可能要问了,那要Sequence和MutableSequence两个抽象基类还有什么作用呢?
其实抽象基类的作用并不是实例化产生实例对象的,它的作用更多的像是定义一种规则,或者官方的说法叫做协议,这样以后我们希望创建这种类型的对象时,要求遵循这种规则或者协议。现在我们需要了解序列类型都有哪些协议,这需要学习abc模块中的Sequence和MutableSequence两个类。
Sequence和MutableSequence两个类的继承关系如下:
图中粗体表示抽象基类,斜体表示抽象方法(抽象方法先有一个印象即可,目前可以先理解为并未做具体实现的方法,后续会专门写一篇文章来介绍抽象方法),剩下的为抽象基类中已经实现的方法。
可以看到,这里面的继承关系并不复杂,但是信息量很大,应该牢记这个图,因为这对理解序列类型非常重要。我们看到,可变序列MutableSequence类继承自不可变序列Sequence类,Sequence类又继承了两个类Reversible和Collection,Collection又继承自Container、Iterable、Sized三个抽象基类。通过这个继承图,我们至少应该能够知道,对于标准不可变序列类型Sequence,应该至少实现以下几种方法(遵循这些协议):
__contains__,__iter__,__len__,__reversed__,__getitem__,index,count
这几个方法到底意味着什么呢?这里以Python的内置类型list为例进行说明:
实现了__contains__方法,就意味着list可以进行成员运算,即使用in和not in;
实现了__iter__方法,意味着list是一个可迭代对象,可以进行for循环、拆包、生成器表达式等多种运算;
实现了__len__方法,意味着可以使用内置函数len()。同时,当判断一个list的布尔值时,如果list没有实现__bool__方法,也会尝试调用__len__方法;
实现了__reversed__方法,意味着可以实现反转操作;
实现了__getitem__方法,意味着可以进行索引和切片操作;
实现了index和count方法,则表示可以按条件取索引和统计频数。
标准的Sequence类型声明了上述方法,这意味着继承自Sequence的子类,其实例化产生的对象将是一个可迭代对象、可以使用for循环、拆包、生成器表达式、in、not in、索引、切片、翻转等等很多操作。这同时也表明,如果我们说一个对象是不可变序列时,暗示这个对象是一个可迭代对象、可以使用for循环、......。
而对于标准可变序列MutableSequence,我们发现,除了要实现不可变序列中几种方法之外,至少还需要实现如下几个方法(遵循这些协议):
__setitem__,__delitem__,insert,append,extend,pop,remove,__iadd__
这几个方法又意味着什么呢?同样以Python的内置类型list为例进行说明:
实现了__setitem__方法,就可以对列表中的元素进行修改,如a = [1,2],代码a[0]=2就是在调用这个方法
实现了__delitem__,pop,remove方法,就可以对列表中的元素进行删除,如a = [1,2],代码del a[0]就是在调用__delitem__方法
实现了insert,append,extend方法,就可以在序列中插入元素;
实现了__iadd__方法,列表就可以进行增量赋值。
这就是说,对于标准可变序列类型,除了执行不可变类型的查询操作之外,其子类的实例对象都可以执行增删改的操作。
鸭子类型
抽象基类Sequence和MutableSequence声明了对于一个序列类型应该实现那些方法,很显然,如果一个类直接继承自Sequence类,内部也重载了Sequence中的七个方法,那么显然这个类一定是序列类型了,MutableSequence的子类也是一样。确实如此,但是当我们查看列表list、字符序列str、元组tuple的继承链时,发现在其mro列表中并没有Sequence和MutableSequence类,也就是说,这些内置类型并没有直接继承自这两个抽象基类,那么为什么我们在文章的开头还要说他们都是序列类型呢?
>>> list.__mro__ (<class 'list'>, <class 'object'>) >>> tuple.__mro__ (<class 'tuple'>, <class 'object'>) >>> str.__mro__ (<class 'str'>, <class 'object'>)
其实,Python中有一种被称为“鸭子类型”的编程风格。在这种风格下,我们并不太关注一个对象的类型是什么,它继承自那个类型,而是关注他能实现那些功能,定义了那些方法。正所谓如果一个东西看起来像鸭子,走起来像鸭子,叫起来像鸭子,那他就是鸭子。
在这种思想之下,如果一个类并不是直接继承自Sequence,但是内部却实现了__contains__,__iter__,__len__,__reversed__,__getitem__,index,count几个方法,我们就可以称之为不可变序列。甚至都不必这么严格,可能只需要实现__len__,__getitem__两个方法就可以称作是不可变序列类型。对于可变序列也同样如此。
鸭子类型的思想贯穿了Python面向对象编程的始终,现在如果不理解没有关系。下一篇文章,我么将介绍不可变序列str,我们会对str和Sequence进行对比,到时候相信大家就能明白。
相关推荐
- 看球直播app下载(看球帝app手机版免费下载)
-
电视直播ios版是一款连接了电视网为您提供电视直播信号的手机直播应用。无论是央视各台还是全国各大卫视都可以在这里免费收看,周五看浙江卫视《中国新歌声》,周六看湖南卫视《快乐大本营》,周末看东方卫视《极...
- 手机测wifi网速在线测试(我的网速测试)
-
在手机上进行Wi-Fi测速,您可以使用以下步骤: 1.打开手机的Wi-Fi功能,并连接到要测试的Wi-Fi网络。 2.打开手机浏览器,访问一个在线Wi-Fi测速网站,例如s...
- 腾讯对战平台官网(腾讯对战平台叫什么名字)
-
用管理员身份运行试试看,不如换个win7,下载一个小白,10分钟搞定。win7现在是市面上电脑最多的系统,兼容各种游戏辅助,各种游戏,各种办公软件,我自己就是win10,新电脑,我换了7,打开腾讯...
- 珍爱网(珍爱网免费征婚交友平台)
-
珍爱网上的人的确是真人,但那些人的资料况你很难判断它的真实性。如何你想在上面找到珍爱,那你得有优秀且真实的资本,要不然珍爱网就是珍爱网而已。灰姑娘很难遇上白马王子,除非你是漂亮的灰姑娘。癞蛤蟆也很难遇...
- 同城约会的app哪个免费(同城约会的app哪个免费好用)
-
玩这类app,最关键的不在软件本身,在于个人实力……能不能约到人?肯定有人成功过,我身边就有这样的例子,一哥们在一个叫么么哒的app上面就成功约到过几个妹子吃饭,代价是他在上面花了几万送女孩礼物淘她们...
- 1 42集免费观看(龙王传说第142集免费观看)
-
脊梁电视剧可以通过手机央视频APP看42集全,因为这部电视剧是在央视频网络平台上进行独播的去爱奇艺APP或者腾讯视频都可以看到读了《中国通史》,我深深感受到我美丽的祖国一中国历史的悠久文化的深远与美丽...
- pp助手源最新地址(pp助手网址是多少)
-
1、打开Cydia。2、进入Cydia后,点击管理中的【软件源】。3、进入到【软件源】页面,点击【编辑】按钮。4、点击【添加】源按钮,跳出添加源弹窗。5、在弹窗中输入需要添加PP助手源地址http:/...
- 直接在手机上刷机软件(用手机给手机刷机的软件)
-
例如使用模拟器就可以第三方的刷机软件,或多或少都是带一点广告的!你要说完全好用的话,只能选奇兔了,奇兔它有专门的ROM移植团队。可以登录它的官网搜索每个品牌的手机的型号都有大神在里面,机型覆盖还是比较...
- 光影app下载(光影app下载正版官方)
-
回答如下:光影是一个Minecraft的模组,可以通过以下步骤下载:1.下载和安装Minecraft的启动器,确保已经安装了Minecraft。2.下载和安装Forge,它是运行Minecraft...
- 十大手游交易平台排行榜(手游交易平台2021前十名)
-
一、咪噜游戏盒子一款时下非常火爆的变态、破解、折扣游戏盒子,为玩家推送变态、无限元宝手游。至尊VIP、海量钻石元宝、独家礼包上线即送,开局你就是土豪。一款专门针对手机游戏爱好者设计推出的福利app平台...
- qq游戏大全(QQ游戏大全列表 百度贴吧)
-
弟弟、牵姐的手一起走--姐姐、牵弟的手一起跑、小小理想--大大梦想、圆规画方--直尺画圆、萎靡开枝的茶--彼岸行走的花、指尖旳太阳--指尖旳月亮、弟、笑着转身--姐、哭着等待、甜甜的、棒棒糖--软软的...
- 笔记本电脑选哪个品牌比较好
-
1、苹果APPLE/美国2、戴尔DELL/美国3、华为HUAWEI/中国4、小米MI/中国5、微软Microsoft/美国6、联想LENOVO/中国7、惠普HP/美国8、华硕ASUS/...
- 10系列显卡排名(10系显卡性能排行)
-
十系显卡指NVIDIAGeForce10系列,是英伟达研发并推出的图形处理器系列,被用以取代NVIDIAGeForce900系列图形处理器。新系列采用帕斯卡微架构来代替之前的麦克斯韦微架构,并...
-
- 最新win7系统下载(windows7最新版本下载)
-
最简单的方法就是,下载完镜像文件后,直接把镜像文件解压,解压到非C盘,然后在解压文件里面找到setup.exe,点击运行即可。安装系统完成后,在C盘找到一个Windows.old(好几个GB,是旧系统打包在这里,垃圾文件了)删除即可。扩展资...
-
2026-01-15 06:43 off999
- 哪个电脑管家软件好用(哪个电脑管家好用些)
-
腾讯电脑管家吧,因为这个是杀毒和管理合一的,占用内存小,因此显得更为简洁,使电脑运行更加流畅此外电脑诊所,工具箱以及4+1的杀毒模式让腾讯电脑管家也收到了广泛的关注4+1杀毒引擎,管家反病毒引擎、金山...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
Python 批量卸载关联包 pip-autoremove
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
