Python代码提升及代码精简教程_第1页
Python代码提升及代码精简教程_第2页
Python代码提升及代码精简教程_第3页
Python代码提升及代码精简教程_第4页
Python代码提升及代码精简教程_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Diet在小型程序中,特别是在脚本中,使用 Python 自带的diet来表示结构信息非常简单方便:>>> ob = 'x':1, 'y':2, 'z':3>>> x = ob'x'>>> ob'y' = y由于在Python 3.6 中diet的实现采用了一组有序键,因此其结构更为紧凑,更深得人心。但是,让我们看看diet在内容中占用的空间大小:>>> print(sys.getsizeof(ob)240如上所示,diet 占用了大量内存,尤

2、其是如果突然虚需要创建大量实例时:实例数对象大小1 000 000240 Mb10 000 0002.40 Gb100 000 00024 Gb类实例有些人希望将所有东西都封装到类中,他们更喜欢将结构定义为可以通过属性名访问的类:elass Point:#def _init_(self, x, y, z):self.x = xself.y = yself.z = z>>> ob = Point(1,2,3)>>> x = ob.x>>> ob.y = y类实例的结构很有趣:字段大小(比特)PyGC_Head24PyObjeet_HEAD16

3、_weakref_8_diet_8合计:56在上表中,_weakref_是该列表的引用,称之为到该对象的弱引用( weakreference );字段 diet是该类的实例字典的引用,其中包含实例属性的值(注意在64-bit 引用平台中占用 8字节)。从 Python 3.3 开始,所有类实例的字典的键都存储在共享空间中。这样就减少了内存中实例的大 小:>>> print(sys.getsizeof(ob), sys.getsizeof(ob._diet )56 112因此,大量类实例在内存中占用的空间少于常规字典( diet ):实例数大小1 000 000168 Mb10

4、 000 0001.68 Gb100 000 00016.8 Gb不难看出,由于实例的字典很大,所以实例依然占用了大量内存。带有slots_的类实例为了大幅降低内存中类实例的大小,我们可以考虑干掉 _diet_ 和_weakref_ 。为此,我们可以借助_slots_:class Point:_slots_ = 'x', 'y', 'z'def _init_(self, x, y, z):self.x = xself.y = yself.z = z>>> ob = Point(1,2,3)>>> print(s

5、ys.getsizeof(ob)64如此一来,内存中的对象就明显变小了:字段大小(比特)PyGC_Head24PyObject_HEAD16x8y8z8总计:64在类的定义中使用了slots以后,大量实例占据的内存就明显减少了:实例数大小1 000 00064 Mb10 000 000640 Mb100 000 0006.4 Gb目前,这是降低类实例占用内存的主要方式。这种方式减少内存的原理为: 在内存中,对象的标题后面存储的是对象的引用(即属性值),访问这些属 性值可以使用类字典中的特殊描述符:>>> pprint(Point._diet ) mappingproxy(&#

6、39;x':member 'x' of 'Point' objects,'y':member 'y' of 'Point' objects,'z':member 'z' of 'Point' objects)为了自动化使用slots创建类的过重,你可以使用库namedlist 。dlist函数可以创建带有_slots_的类:>>> Point = namedlist('Point', ('x

7、', 'y', 'z')还有一个包attrs ,无论使用或不使用_slots_都可以利用这个包自动创建类。元组Python 还有一个自带的元组(tuple )类型,代表不可修改的数据结构。元 组是固定的结构或记录,但它不包含字段名称。你可以利用字段索引访问元 组的字段。在创建元组实例时,元组的字段会一次性关联到值对象:> >> ob = (1,2,3)> >> x = ob0> >> ob1 = y # ERROR元组实例非常紧凑:> >> print(sys.getsizeof(o

8、b)72由于内存中的元组还包含字段数,因此需要占据内存的8个字节,多于带有_slots_的类:字段大小(字节)PyGC_Head24PyObject_HEAD16ob_size8081828总计:72命名元组由于元组的使用非常广泛,所以终有一天你需要通过名称访问元组。为了满足这种需求,你可以使用模块dtuple 。 namedtuple 函数可以自动生成这种类:>>> Point = namedtuple('Point', ('x', 'y', 'z')如上代码创建了元组的子类,其

9、中还定义了通过名称访问字段的描述符。对于上述示例,访问方式如下:class Point(tuple):#propertydef _get_x(self):return self0propertydef _get_y(self):return self1propertydef _get_z(self):return self2#def _new_(cls, x, y, z):return tuple._new_(cls, (x, y, z)这种类所有的实例所占用的内存与元组完全相同。但大量的实例占用的内存也会稍稍多一些:实例数大小1 000 00072 Mb10 000 000720 Mb100

10、 000 0007.2 Gb记录类:不带循环 GC的可变更命名元组由于元组及其相应的命名元组类能够生成不可修改的对象,因此类似于ob.x的对象值不能再被赋予其他值,所以有时还需要可修改的命名元组。由 于Python没有相当于元组且支持赋值的内置类型,因此人们想了许多办法。在这里我们讨论一下记录类( recordclass ,),它在 StackoverFlow 上广受 好评。此外,它还可以将对象占用的内存量减少到与元组对象差不多的水平。recordclass 包弓I入了类型 recordclass.mutabletuple ,它几乎等价于元组,但 它支持赋值。它会创建几乎与namedtuple

11、完全一致的子类,但支持给属性赋新值(而不需要创建新的实例)。 recordclass函数与namedtuple函数类 似,可以自动创建这些类:>>> Point = recordclass('Point', ('x', 'y', 'z')>>> ob = Point(1,2, 3)类实例的结构也类似于tuple ,但没有PyGC_Head :字段大小(字节)PyObject_HEAD16ob_size8x8y8z8总计:48在默认情况下,recordclass函数会创建一个类,该类不参与垃圾回收

12、机制。一般来说,namedtuple 和recordclass都可以生成表示记录或简单数据结构(即非递归结构)的类。在 Python中正确使用这二者不会造成循环引用。因此,recordclass生成的类实例默认情况下不包含PyGC_Head片段(这个片段是支持循环垃圾回收机制的必需字段,或者更准确地说,在创还类的PyTypeObject结构中,flags字段默认情况下不会设置Py_TPFLAGS_HAVE_GC标志)。大量实例占用的内存量要小于带有_slots_的类实例:实例数大小1 000 00048 Mb10 000 000480 Mb100 000 0004.8 Gbdataobject

13、recordclass 库提出的另一个解决方案的基本想法为:内存结构采用与带_slots_ 的类实例同样的结构,但不参与循环垃圾回收机制。这种类可以通过 recordclass.make_dataclass函数生成:>>> Point = make_dataclass('Point', ('x', 'y', 'z')这种方式创建的类斯认会生成可修改的实例。另一种方法是从recordclass.dataobject 继承:class Point(dataobject):x:inty:intz:int这种方法创建的类

14、实例不会参与循环垃圾回收机制。内存中实例的结构与带 有_slots_的类相同,但没有 PyGC_Head :字段大小(字节)PyObject_HEAD16ob_size8x8y8z8总计:48>>> ob = Point(1,2,3)>>> print(sys.getsizeof(ob)40如果想访问字段,则需要使用特殊的描述符来表示从对象开头算起的偏移量, 其位置位于类字典内:mappingproxy(_new_': <staticmethod at 0x7f203c4e6be0,'x': <recordclass.da

15、taobject.datas10tgetset at 0x7f203c55c690>,'y': <recordclass.dataobject.datas10tgetset at 0x7f203c55c670,'z': <recordclass.dataobject.datas10tgetset at 0x7f203c55c410>)大量实例占用的内存量在CPython 实现中是最小的:Cython还有一个基于 Cython (/ )的方案。该方案的优点是字段可 以使用C语言的原子类型。访问字段的描述符可

16、以通过纯Python 创建。例如:cdef class Python:cdef public int x, y, zdef _init_(self, x, y, z): self.x = xself.y = yself.z = z本例中实例占用的内存更小:>>> ob = Point(1,2,3)>>> print(sys.getsizeof(ob)32内存结构如下:字段PyObject_HEAD大小(字节)16x4y4z4nycto4总计:32大量副本所占用的内存量也很小:实例数大小1 000 00032 Mb10 000 000320 Mb100 000 0003.2 Gb但是,需要记住在从 Python代码访问时,每次访问都会引发int 类型和Python 对象之间的转换。Numpy使用拥有大量数据的多维数组或记录数组会占用大量内存。但是,为了有效地利用纯Python 处理数据,你应该使用Numpy包提供的函数。>>> Point = numpy.dtype('x', 32), ('y', 32), ('z', 32)一个拥有N个元素、初始化成零的数组可以通过下面的函数创建

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论