暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

python面向对象编程篇(11):省内存的__slots_

小儿来一壶枸杞酒泡茶 2021-03-16
266

本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。

个人其他博客地址:

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

小钟同学 | 文 【原创】| QQ:308711822

1 前言

我们的知道python动态性让我们的可以为所欲为。甚至是运行时可以动态的新增属性。但是这种任意性有时候也是需要要付出代价的。那就是我们的对象可能需要新增更多的内存的开销。

2 关于类中的__dict__属性

python类中有内置的属性__dict__,它是一个python类中默认用来存储一个对象的实例属性的一个字典。

但是不是所有的类都有这个__dict__属性, 如:常见的容器对象

dd = []
dd.__dict__

此时的结果是:

Traceback (most recent call last):
 File "D:/code/python/local_python/AntFlask/ceshi2.py", line 5, in <module>
   dd.__dict__
AttributeError: 'list' object has no attribute '__dict__'

而自定义的类通常默认的是会有__dict__属性:

class Ape:
   # 定义__call__方法
   def __init__(self,name):
       self.name = name

print(Ape.__dict__)
a = Ape('妈妈')
print(a.__dict__)

输出的结果为:

{'__module__''__main__''__init__': <function Ape.__init__ at 0x000001C58E4B3D08>, '__dict__': <attribute '__dict__' of 'Ape' objects>, '__weakref__': <attribute '__weakref__' of 'Ape' objects>, '__doc__': None}
{'name''妈妈'}

关于继承的一个示例:

class Ape:
   # 定义__call__方法
   def __init__(self, name):
       self.name = name


print(Ape.__dict__)
a = Ape('妈妈')
print(a.__dict__)


class KAS(Ape):
   kkkk = '啊啊啊'


print(KAS.__dict__)
a = KAS('新的世界')
print(a.__dict__)


输出:

{'__module__''__main__''__init__': <function Ape.__init__ at 0x000001AB1B633D08>, '__dict__': <attribute '__dict__' of 'Ape' objects>, '__weakref__': <attribute '__weakref__' of 'Ape' objects>, '__doc__': None}
{'name''妈妈'}
{'__module__''__main__''kkkk''啊啊啊''__doc__': None}
{'name''新的世界'}

关于__dict__属性的总结:

  • python内置的数据类型没有__dict__属性

  • 对象有自己的属性,保存的是对象自身的属性信息

  • 每个类也有自己的__dict__属性

  • 父类的__dict__ 并不会影响子类的__dict__

  • 子类和父类的实例对象共享同一个__dict__

3 __slots__限制类实例绑定的属性,不要额外的分配太多其他无关的属性

__slots__可以用于限制我们的示例属性的绑定,意思就是只限制固定的分配几个属性值,其他不需要分配。

作用:

  • 限制类实例动态添加属性和方法
  • 避免用户频繁的给实例对象动态地添加属性或方法

注意点:

  • slots 只能限制【实例对象】动态添加属性和方法
  • slots 不能限制 【类】 动态添加属性和方法

如下示例:

没有限制的情况下


class Ape:
    # 定义__call__方法
    def __init__(self, name):
        self.name = name


from memory_profiler import profile

@profile(precision=4)
def my_func():
    return [Ape("as" + str(i)) for i in range(1000000)]


my_func()


查看输出:

Filename: D:/code/python/local_python/AntFlask/ceshi2.py

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    12  18.8438 MiB  18.8438 MiB           1   @profile(precision=4)
    13                                         def my_func():
    14 251.7539 MiB -775.8594 MiB     1000003       return [Ape("as" + str(i)) for i in range(1000000)]

加了限制之后:

class Ape:
    __slots__ = ['name']
    def __init__(self, name):
        self.name = name


from memory_profiler import profile

@profile(precision=4)
def my_func():
    return [Ape("as" + str(i)) for i in range(1000000)]


my_func()


输出结果:

Filename: D:/code/python/local_python/AntFlask/ceshi2.py

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    12  18.9258 MiB  18.9258 MiB           1   @profile(precision=4)
    13                                         def my_func():
    14 134.9531 MiB -3311.0977 MiB     1000003       return [Ape("as" + str(i)) for i in range(1000000)]


输出的内存结果的说明:参数说明:

  • line  已分析的代码的行号
  • Mem usage:表示执行该行后Python解释器的内存使用情况
  • Increment:表示当前行的内存相对于上一行的差异,即自己本身增长了多少,如果减少了则不显示.


End

纯属个人实践中相关经验阐述总结,如有纰漏,还希望大佬们多多提点!小钟同学 | 文  【原创】| QQ:308711822


文章转载自小儿来一壶枸杞酒泡茶,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论