Python __slots__ 作用和意义 以及部分示例

__slots__是Python中的一种特殊类属性,用于优化内存使用、提高属性访问速度,并限制实例的动态属性。它通过在类定义时指定固定的属性列表,减少__dict__的内存消耗,适合大规模实例且对内存效率要求高的场景。
摘要由CSDN通过智能技术生成

__slots__ 说明

在 Python 中,__slots__ 是一个特殊类属性,用于声明该类的实例将如何管理其属性。当一个类定义了 __slots__,它指示 Python 解释器以一种更高效、更紧凑的方式来存储实例属性,而不是使用通常的字典(__dict__)来存放每个实例的所有动态属性。

以下是 __slots__ 主要特点和用途:

  1. 内存优化:常规情况下,Python 类的实例会自动拥有一个 __dict__ 属性,这是一个字典,用于存储实例的所有动态属性(即在类定义之外添加的属性)。字典本身有一定的内存开销,而且对于大量实例来说,这些开销会累积。使用 __slots__ 后,Python 不再为每个实例创建 __dict__,而是直接在对象内部分配固定大小的空间来存储指定的属性,从而减少了内存使用。

  2. 更快的属性访问:由于属性直接存放在对象内部的固定位置,访问 __slots__ 中声明的属性通常比访问普通字典中的属性更快,因为避免了字典查找操作。这意味着在频繁访问属性的性能敏感场景中,使用 __slots__ 可能带来显著的性能提升。

  3. 限制动态属性:默认情况下,Python 实例可以随时添加新的属性。然而,通过定义 __slots__,您实际上是在告诉 Python 这个类的实例只允许拥有 __slots__ 中列出的属性,不允许添加其他未声明的属性。这有助于实现更严格的对象结构控制,减少编程错误,特别是在大型项目或对内存使用有严格要求的系统中。

  4. 使用语法:在类定义中,__slots__ 应该是一个包含属性名称的元组、列表或字符串。如果属性名称仅为单个字符串,则可以省略括号。例如:

    class MyClass:
        __slots__ = ('attr1', 'attr2')  # 定义两个允许的属性
    
    class AnotherClass:
        __slots__ = 'attr'  # 单个属性时可省略括号
    

    如果需要为子类继承父类的 __slots__,则需要显式地在子类中重新声明(或者扩展)__slots__

  5. 注意事项

    • 不适用于动态添加属性:如果类的实例需要频繁地添加或删除未在 __slots__ 中预定义的属性,那么使用 __slots__ 可能不合适,因为它限制了这种灵活性。
    • 不支持 __dict____weakref__:除非在 __slots__ 中明确列出,否则使用 __slots__ 的类的实例将无法拥有 __dict____weakref__ 属性。若需要这两个属性,应将其包含在 __slots__ 中。
    • 仅影响直接实例__slots__ 的效果不会自动传递给子类。子类需要各自独立地定义 __slots__,如果需要继承父类的 __slots__,需要显式包含。

总的来说,__slots__ 是一种优化手段,用于在特定场景下减少内存占用和提高属性访问速度,同时可以作为一种实现对象属性约束的机制。是否使用 __slots__ 应根据具体的应用场景、类的实例数量、对内存效率的需求以及是否需要动态添加属性等因素综合考虑。在大规模实例创建或内存资源有限的情况下,合理使用 __slots__ 可能带来显著的益处。

个人测试代码

import typing as t

from pych1 import Man # 此为我自己定义的普通类,如果错误请删除换自己的或直接丢弃

class SlotClassName:

    outername = None
    whd = None

    __slots__ = ('name', 'age', 'num', 'issue', 'longlong', 'maybe')

    def __init__(self, **kwargs) -> None:
        self.name: t.Dict[str, t.Any] = kwargs
        self.num: Man.Man = None
        self.issue: int = 0
        self.longlong: int = 0
        self.maybe: t.Dict = kwargs


if __name__ == '__main__':

    x1 = SlotClassName(a=1, b=2, c=3, d=4)
    print(x1)

但当我试图在构造方法中对slot 外部的属性进行修改时发现执行错误,提示是只读,不能修改

    def __init__(self, **kwargs) -> None:
        self.whd:t.Any = 0
        self.outername:str = '1'
        ................
        ................

报错如下:

AttributeError: 'SlotClassName' object attribute 'outername' is read-only

显然无法修改,但是修改其他在 slot 内的是可以的,在实际其他人的使用中也发现,放到 slot 外的属性基本都直接在外部赋值了,后续没有其他操作,用于存放一些不会变的数据

继承上面类中的属性:

class ExtendsSlot(SlotClassName):

    __slots__ = { 'hahaha', 'qwe'}

    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)
        self.issue = 9
        self.hahaha = 1


if __name__ == '__main__':
    x1 = ExtendsSlot()
    print(x1)

执行成功,可以修改成功继承的属性,同时父类 slots 内外的属性都被继承了,但父类slots 外的属性依旧无法修改,会报同样的错误

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值