详解python 内存优化
写在之前
围绕类的话题,说是说不完的,仅在特殊方法,除了我们在前面遇到过的__init__(),__new__(),__str__()等之外还有很多。虽然它们只是在某些特殊的场景中才会用到,但是学会它们却可以成为你熟悉这门语言路上的铺路石。
所以我会在试图介绍一些「黑魔法」,让大家多多感受一下Python的魅力所在,俗话说「艺多不压身」就是这个道理了。
内存优化
首先先让我们从复习前面的类属性和实例属性的知识来引出另一个特殊方法:
>>>classSample: ...name='rocky' ...
就像前面的文章我们所说的,每个类都有一个__dict__()属性,它包含了当前类的类属性:
>>>Sample.__dict__ mappingproxy({'__module__':'__main__','name':'rocky','__dict__':,'__weakref__': ,'__doc__':None}) >>>Sample.name 'rocky'
同样,如果我们创建了实例,每个实例也有一个__dict__属性,它里面就是当前的实例属性:
>>>a=Sample() >>>a.__dict__ {} >>>a.age=23 >>>a.__dict__ {'age':23}
上面的操作可以看出,当实例刚刚创建的时候,__dict__是空的,只有创建了实例属性以后,它才包含其内容。实例的__dict__和类的__dict__是有所区别的,即实例属性和类属性是不同的。
从理论上来说,我们可以根据一个类创建无数的实例,新建一个实例以后,又创建了一个新的__dict__,这将是一个很可怕的事情,虽然每个__dict__所占的内存空间很小,当然这件事事实上是不会出现的。但是程序不能建立在这种不可靠的猜测的基础上,程序要对过程有明确的控制。
所以就要有一种方法能够控制__dict__,于是「__slots__」应运而生。
>>>classNature: ...__slots__=('tree','flower') ... >>>dir(Nature) ['__class__','__delattr__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__slots__','__str__','__subclasshook__','flower','tree']
我们仔细来看dir()的结果,发现__dict__属性没有了,也就是说__slots__把__dict__挤出去了,它进入了类的属性。
>>>Nature.__slots__ ('tree','flower')
从这里可以看出,类Nature有且仅有两个属性。从类的角度来看,其类属性只有这两个;从实例的角度来看,其实例属性也只有这两个。
>>>Nature.tree='liushu' >>>Nature.tree 'liushu' >>>Nature.tree='lishu' >>>Nature.tree 'lishu'
通过类可以对属性进行赋值和修改,这个似乎和以前的类属性没有什么区别,别着急,继续往下看就看到区别了:
>>>x=Nature() >>>x.__slots__ ('tree','flower') >>>y=Nature() >>>y.__slots__ ('tree','flower') >>>id(x.__slots__) 4531629384 >>>id(y.__slots__) 4531629384
你看,实例化以后,实例的__slots__和类的__slots__完全一样,这跟前面的__dict__大不一样了。并且我们建立了两个实例,结果发现两个实例的__slots__在内存中居然是一个,或者可以说是增加实例时__slots__并不增加。
>>>x.tree 'lishu' >>>y.tree 'lishu'
既然类属性已经赋值,那么通过任何一个实例属性都能得到同样的值,不过这时候不能通过实例修改此属性的值。
>>>x.tree='taoshu' Traceback(mostrecentcalllast): File"",line1,in AttributeError:'Nature'objectattribute'tree'isread-only
对实例属性来说,类的静态数据是只读的,不能修改,只有通过类属性才能修改。但对于尚未赋值的属性,能够通过实例赋值。
>>>x.flower='rose' >>>x.flower 'rose' >>>x.flower='moli'
显然通过实例操作的属性,也能够通过实例修改,但是实例属性的值并不能够修改类属性的值
Nature.flower
由上面可以看出,实例属性的值并没有传回给类属性,也可以理解为新建了一个同名字的实例属性,如果再给类属性赋值的话,则会像下面一样:
>>>Nature.flower='huaihua' >>>x.flower 'huaihua'
类属性对实例属性具有决定作用,对实例而言,通过类所定义的属性都是只读的。
__slots__已经把实例属性牢牢的看管起来,只能是指定的属性,如果想要增加属性的话,只能通过类属性来实现,所以__slots__的一个重要作用就是优化了内存。
写在之后
当然了,__slots__还能加快属性加载速度,这个不是本文的重点,所以不做过多的介绍,感兴趣的可以去Google一下。
今天的文章就到这里啦,明天讲一下「属性拦截」,又是新的一周,燥起来!
如果你觉得文章对你有帮助的话,欢迎点赞转发,让更多的人看到,谢谢啦。
Theend。
以上就是详解python内存优化的详细内容,更多关于python内存优化的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。