Python的特殊属性: __slots__

在Python中不知存在着特殊方法(魔术方法),还存在着特殊属性:__slots__

在Python中,用户自定义的类的属性会默认保存在 __dict__ 属性中。__dict__ 属性对应的是一个用来储存类属性的字典。字典内的值可以通过简单的语句 instanceName.__dict__ 直接查看,和查看一个普通的类属性一样。

而 __slots__ 属性的作用就是:取代 __dict__ 属性,将类属性保存到 __slots__ 中。__slots__ 属性是一个元组,具体用法如下:

# Python version: 3.7

>>> class Cat():                        # 定义一个类
...     def __init__(self):             # 初始化属性:name 和 age
...         self.name = 'hello kitty'
...         self.age = 3
...     
...     __slots__ = ('name', 'age')     # 启用 __slots__ 并注意赋值不带self,且是字符串格式
... 
>>> my_cat = Cat()                      # 创建一个实例 my_cat
>>> my_cat.__dict__                     # 查看 __dict__ 属性,发现未定义
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Cat' object has no attribute '__dict__'
>>> my_cat.__slots__                    # 查看 __slots__ 发现正常显示出来属性名
('name', 'age')
>>> my_cat.name                         # 也能正常访问属性
'hello kitty'
                                        # 尝试创建新的属性,失败
>>> my_cat.high = 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Cat' object has no attribute 'high'

可以看到,在 my_cat 实例中找不到 __dict__ 属性,但是可以调用 __slots__ 属性。

为什么要用 __slots__ 属性来取代默认的 __dict__ 属性来保存类属性呢?

因为 __dict__ 保存属性的方式是字典,Python的字典功能很强大,优点多多,甚至具有能无视数据量的查找速度(详情请看《流畅的Python》3.9.1 一个关于效率的实验)。但字典唯一的缺点恐怕就是内存开支了。因为字典需要存储散列表,而散列表本身也会占用内存资源,这就导致内存的巨大开销——你定义了一个字典,你不止在字典里存储了你想存储的数据,还建立了一个规模大于你数据量三分之一以上的散列表!

出于这个原因,如果你定义的类需要构建大量的实例,那么改用 __slots__ 属性的元组存储方式来存储类属性能节省大量的内存资源。而且元组的速度也很快

使用 __slots__ 的副作用:

使用 __slots__ 也会带来副作用,你将无法动态的往实例里添加属性,因为元组的不可变性质。如果你希望在使用 __slots__ 后还能正常的往实例里动态的添加新属性,可以在 __slots__ 中增加 “__dict__”值。这样子的话,预先定义的属性将会被存储到__slots__ 中,而动态增加的属性将会被添加到 __dict__ 中,也就是重新启用 __dict__ 。

此外,还有一个实例属性可能需要注意,即 __weakref__ 属性,为了让对象支持弱引用,必须有这个属性。用户定义的类中默认就有 __weakref__ 属性。可是,如果类中定义了 __slots__ 属性,而且想把实例作为弱引用的目标,那么要把‘__weakref__’添加到 __slots__ 中。
还有一点就是, __slots__ 只在当前定义的类中有效,用这个类所派生出的子类是不继承 __slots__ 属性的,如有需要则需重新定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值