当前位置: 首页 > Linux

Python对象的空间边界:孤独与开放与包容

时间:2023-04-06 20:01:06 Linux

简介:Python猫是猫来客,它热爱地球上的一切,尤其是优雅无所不能的Python。我是它的人类朋友,豌豆花下的猫,授权我润色和发布它的文章。如果你是第一次阅读本系列文章,那么我强烈推荐你阅读它写的前两篇文章(见文末链接),相信你会爱上这种神秘的哲学+极客猫。话不多说,一起来享受今天的“思想盛宴”吧!睡觉是我最喜欢做的事——因为我可以懒洋洋地做梦,不吃饭,不与人争吵,不为世事操心。这是我除了学习Python和写作之外最舒服的事情。于是,刚睡醒,又犯困了……刚看到Python之父Guido的邮件,说要“回到休眠模式”,不参与正在进行的PEP投票。哼,这个懒惰的老头——等我,我写完这篇文章就回去睡觉了……我上次说了,我发现Python公民的身份和毕达哥拉斯拉斯的哲学命题不谋而合(一切都是数字)真是令人费解。在梦里,我已经想出了答案。可突然,一条大蟒蛇游了上来,将答案吞了下去。我去找它讲道理,它就开始耍花样,吞自己的尾巴、屁股、肚子……最后把自己全吞了。las,可怜的我的回答就这样消失了。今天继续和大家聊聊Python中与身份密切相关的一个话题,即对象的边界问题。如你所知,我本来是一只猫,现在有点像人,但在这个转变过程中,我非常敏感,总是能想象到其中的微妙之处,最后幸运地有所收获。希望我的分享也能启发你哪怕是一点点的见识,那我就很开心了:)1.固定的界限:自由与孤独的界限划得很清楚。礼貌的人称它们为定长对象,或不可变的对象,然而,知道一些历史典故的人称它们为铁公鸡。这个典故从何而来?还好毛毛,我有点历史常识,知道这指的是激进的道教弟子杨朱。为利天下,失一分钱,不还;学会服务于世界,你就不会接受;人人不失一分钱,人人利天下,天下就治!——春秋·杨朱一个定长对象,你不能给它加元素,不能给它减元素,不能给它修改元素,甚至不能轻易复制删除!(参见本公众号Python猫中关于字符串的系列文章,链接在文末)这些对象在世界上独树一帜,也与世界隔绝。你看,他们的外表平凡普通,但他们的灵魂是自由的,生命是尊严的,不可侵犯的。想要对付这些市民,就得随他们的脾气,不要太过分了。>>>t1=('Python','cat')>>>t2=('Python','cat')>>>t1ist2#objectindependentFalse>>>t1[1]='snake'#UnmodifiableelementsTypeErrorTraceback(mostrecentcalllast)TypeError:'tuple'objectdoesnotsupportitemassignment在上一篇文章中,我们看到了Python世界中的“特权种族”,特权种族无一例外都是为定长而生对象。它们是一脉相承的,它们存在的道理也是相似的,就是方便共享内存资源,提高内存使用效率。上表是定长对象列表。可以看出,他们占据了大多数。定长对象的特性让我想到了一种人。他们严守自己的界限,刻板严谨,只关心自己的职责,默默承担责任,追求内心的自由。虽然他们会经常和别人打交道,但他们并不寻求扩大自己的利益,也不想侵犯别人的领地。独立个体发展个人品牌,他们的不变性创造了外人可以依赖的确定性。>>>key1='Pythoncat'>>>key2=['someoneelse']>>>dict1={key1:'goodguy'}{'Pythoncat':'niceguy'}>>>dict2={key2:'Goodguy'}TypeErrorTraceback(mostrecentcalllast)TypeError:unhashabletype:'list'为了保持定长对象的独立性/确定性,Python在编译机制上做了很多优化,比如作为Intern机制和constantmerge机制。这样的好处,我已经提过很多次了。还有一个缺点,那就是孤独。他们的孤独不在于他们没有自己的同类,而在于他们无法(不容易)复制自己。以字符串对象为例,你可以尝试多种方法,但到最后,你发现唯一通用的方法就是先“把字符串撕成万段”,然后再重新组装!s0="Pythoncat"#下面7个方法不能复制s0字符串,id(x)==id(s0)s1=s0s2=str(s0)s3=s0[:]s4=s0+''s5='%s'%s0s6=s0*1importcopies7=copy.copy(s0)#下面的方法可以复制字符串,“打断”并重新组合s8=“”.join(s0)哲学上有一个著名的脑洞:如果a人被粉碎成原子又重新组合,这个人还是原来的那个人吗?这个问题可以让古往今来的哲人斗智斗勇,如果放到今天的热播电视剧《奇葩说》上,也可以让辩论者“一本正经地胡说八道”没完没了。在Python的世界里,就没有这样的麻烦,因为判断两个对象是否相同的标准是一定的,就是它们的id是否相等。因此,用Python来回答这个问题,答案会是:如果用join()方法把字符串打碎成字符再组合起来,新的字符串就不再是原来的字符串了。过程很“残忍”,但总算可以一点点排解一个自由个体的孤独。2、弹性边界:开放和约束不同于定长对象,变长对象/可变对象信奉另一套哲学。他们心胸开阔,处事包容,因地制宜地拓宽自己的界限。以列表对象为例。它愿意接受所有其他对象,愿意在动态规划上花费精力,也不怕把身上的“头发”都拔光。>>>l=['Python','cat']>>>l.append('othercat')#['Python','cat','othercat']>>>l.pop(1)#['Python','Othercats']>>>l.clear()#[]这些大胆的行为在定长对象中是不可想象的。在变长对象中,你似乎能够感受到一种包容的风度。相比之下,定长物体中的铁公鸡形象立马显得太小了。可变长度对象并非没有边界。相反,他们更关心自己的边界,并花费大量资源来维持动态稳定性。界线一经确立,就决不允许越界。和一些编程语言动不动就数组越界不同,Python没有切片越界,因为切片操作总是被控制在范围内,超出索引的部分会被自动丢弃。>>>q=[1,2,3,4,5]#不允许索引超出范围>>>q[10]IndexErrorTraceback(mostrecentcalllast)IndexError:listindexoutofrange#Allowsliceoutofrange>>>q[2:10]#[3,4,5]>>>q[-10:2]#[1,2]变长对象本质上是一个可伸缩的容器,其主要优点是支持连续添加或删除元素。对应计算机硬件水平,就是不断申请或释放内存空间。这样的操作是开销很大的操作,为了减少开销,Python巧妙地设计了分配多余空间的机制。以list为例,在内存充足的前提下,list在最初创建的时候并没有分配多余的空间。append()第一次扩展列表时,Python会按照下面的公式分配多余的空间,即分配大于列表中实际元素个数的内存之后,每次扩展操作先检查是否有多余的空间space,有则直接使用,没有则重新计算,多余的空间重新分配。公式如下:new_allocated=(newsize>>3)+(newsize<9?3:6)其中,new_allocated指的是超分配的内存大小,newsize是扩展元素的实际长度。比如一个长度为4的list,append()添加一个元素,实际长度为5(即newsize为5)。但是Python不会只给它分配5个内存空间,而是经过计算给它超分配了new_allocated==3个内存大小,所以最后,list的元素实际占用的内存空间是8个。在这个way,当list再次扩容时,只要最终长度不大于8,就不需要申请新的内存空间。当扩容后的长度等于9时,new_allocated等于7,即额外获得7块内存大小,以此类推。以列表的长度为横轴,过度分配的内存大小为纵轴,得到如下精彩图表:意味着他们在发展上有大胆的计划和适度的克制。从这点来看,与“自封”的定长对象相比,变长对象既开明又理性。3.结语回顾上面提到的定长对象,很佩服它们的个性。铁公鸡形象虽略显吝啬,但对人无害。反而能感受到其浓浓的“富贵不能淫,贫贱不能移,威武不屈”的男子气概。再看变长对象,“本来就什么都没有”,却可以包容一切,信任他人,对外开放。更难得的是,他们有张弛有度,孕育着无限可能。这两个对象极大地满足了我对Python世界的好奇心,也成为了我认识自己和人类世界的一个参照系。精彩的!精彩的!如果你问,我更欣赏哪一类?喵喵,我有点饿了,我找几条鱼干,吃饱肚子再说吧……Python猫的往事:用Python,我可以叫所有猫的名字Python对象的身份神话:来自所有公民到一切都是字符串系列:你真的知道什么是Python字符串吗?你真的知道如何使用Python字符串吗?Python支持复制字符串吗?join()方法的妙用与Intern机制的弱点----------------本文首发于微信公众号【Python猫】,转载后台回复“爱学习”,免费获取20+精选电子书。