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__ 属性的,如有需要则需重新定义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`__slots__` 是 Python 中的一个特殊属性,它允许你显式地指定一个类的实例属性。通过使用 `__slots__`,你可以限制一个类实例可以存在的属性集合,从而优化内存使用和访问速度。 在 Python 中,每个类实例都有一个字典(`__dict__`)用于存储实例的属性。这使得你可以在运行时动态地给实例添加、修改或删除属性。然而,对于拥有大量实例的类,使用字典来存储属性可能会占用大量内存,并且属性查找会比较慢。 使用 `__slots__`,你可以预先声明一个固定的属性集合,从而避免了使用字典来存储实例的属性。通过这种方式,每个实例只会使用固定大小的内存,属性查找也变得更快。 要使用 `__slots__`,你可以在类定义中定义一个包含属性名称的元组。这些属性名称将成为实例的属性,而且除了这些属性之外,任何其他的属性都不能被添加到实例中。以下是一个示例: ```python class MyClass: __slots__ = ('attribute1', 'attribute2') def __init__(self, value1, value2): self.attribute1 = value1 self.attribute2 = value2 # 创建一个类实例 obj = MyClass(10, 20) # 访问实例属性 print(obj.attribute1) # 输出: 10 print(obj.attribute2) # 输出: 20 # 尝试添加新属性 obj.attribute3 = 30 # 抛出 AttributeError:'MyClass' object has no attribute 'attribute3' ``` 在上面的例子中,`MyClass` 类的实例只能具有 `attribute1` 和 `attribute2` 这两个属性。如果你尝试添加一个不在 `__slots__` 中的新属性,将会引发 `AttributeError` 异常。 需要注意的是,使用 `__slots__` 有一些限制和注意事项: - `__slots__` 只对当前类的实例有效,子类不受影响。 - 每个类实例仍然会有一个 `__dict__` 属性,但它只是一个空字典,不会包含实例的属性。 - 使用 `__slots__` 可能会导致一些特殊方法(例如 `__weakref__`)无法正常工作。 - 使用 `__slots__` 可能会限制动态性和灵活性。只有在确实需要优化内存和属性访问速度时才应该使用它。 希望这个解释能够帮到你!如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值