一、如何限制属性
1.给类或者示例添加属性和方法
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,对于class本身也是一样的
2.使用__slots__
如果先要对class和实例加以限制,可以在定义class的时候,定义一个__slots__,来限制能够添加的属性:
这么做之后,没在__slots__里面标记好的属性就不能随便添加到类或者示例中了
二、如何节省内存
1.方法
在默认情况下,Python的新类和旧类的实例都有一个字典来存储属性值。这对于那些没有实例属性的对象来说太浪费空间了,当需要创建大量实例的时候,这个问题变得尤为突出。
因此这种默认的做法可以通过在新式类中定义了一个__slots__属性从而得到了解决。__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量,因此没有为每个实例都创建一个字典,从而节省空间。
2.原理
和list相比,dict 查找和插入的速度极快,不会随着key的增加而增加;dict需要占用大量的内存,内存浪费多。而list查找和插入的时间随着元素的增加而增加;占用空间小,浪费的内存很少。python解释器是Cpython,这两个数据结构应该对应C的哈希表和数组。因为哈希表需要额外内存记录映射关系,而数组只需要通过索引就能计算出下一个节点的位置,所以哈希表占用的内存比数组大,也就是dict比list占用的内存更大。
3.测试
是骡子是马,牵出来溜溜就知道
首先安装memory_profiler
pip install memory_profiler
编写测试脚本
from memory_profiler import profile
class Foobar():
def __init__(self, x):
self.xx = x
@profile
def main():
f = [Foobar(i) for i in range(1000000)]
if __name__ == '__main__':
main()
运行结果
重新通过__slots__来实现
from memory_profiler import profile
class Foobar():
__slots__ = ['xx',]
def __init__(self, x):
self.xx = x
@profile
def main():
f = [Foobar(i) for i in range(1000000)]
if __name__ == '__main__':
main()
结果:
实测在mac上,用pycharm跑节省了大约一半的内存
4.总结
在确定类的属性值固定的情况下,可以使用__slots__方式对内存进行优化。但是这项技术不应该被滥用于静态类或者其他类似场合,那不是python程序的精神所在。
参考:https://m.jb51.net/article/146854.htm