前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python __slots__ 简介

Python __slots__ 简介

作者头像
为为为什么
发布2022-08-06 11:26:14
4920
发布2022-08-06 11:26:14
举报
文章被收录于专栏:又见苍岚又见苍岚

当一个类需要创建大量实例时,可以通过__slots__声明实例所需要的属性,本文介绍__slots__相关内容。

简介

Python 中一切皆为对象,类也是如此,类中的变量具有强大的动态灵活性,这依赖于变量实现了类似字典管理的机制。但当我们需要限制实例的属性时该如何实现?

限制变量范围

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

代码语言:javascript
复制
class Student:
     __slots__ = ('name', 'age')

s = Student()
s.name = 'digg'  ## OK
s.age = '19'  ## OK

s.score = 99 ## ERROR

-->
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

由于’score’没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

提升成员访问性能

__slots__ 变量设置了类访问成员的活动范围,舍弃了原始Python类的灵活性,但是收益是类成员访问效率的提升。

python文档中这样介绍它

3.3.2.4. *slots* slots 允许我们显式地声明数据成员(例如特征属性)并禁止创建 dictweakref (除非是在 slots 中显式地声明或是在父类中可用。) 相比使用 dict 此方式可以显著地节省空间。 属性查找速度也可得到显著的提升。

python的动态性一部分源自于__dict__,属性都保存在__dict__的一个字典中,我们可以随时向这个字典添加新内容,这是MonkeyPatch的能力。 而当我们显示的声明了__slots__,python将不会给这个类创建__dict____weakref__

注: __weakref__是软引用,类似于指针,不会增加引用计数器

继承问题

但是__slots__遇到继承时,就会出现很多问题。准确的说,__slots__不会被继承。当我们用一个不带有__slots__的子类,继承带有__slots__的父类时。子类还是会生成__dict____weakref__

为解决__slots__无法继承的问题可以采用 metaclass 的能力。

代码语言:javascript
复制
class SlotsMeta(type):
    def __new__(mcs, *args, **kwargs):
        if super_class := args[1]:
            if getattr(super_class[0], "__slots__", None):
                __attr = args[2]
                if not __attr.get("__slots__"):
                    __attr["__slots__"] = ()
                    args = (args[0], args[1], __attr)
        return super().__new__(mcs, *args, **kwargs)


class SlotsClass(metaclass=SlotsMeta):
    __slots__ = ('a', 'b', 'c')

    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3


class SubClass(SlotsClass):

    def __init__(self):
        self.d = 4
        self.e = 5
        self.a = 7

  • 这个Metaclass 在被单继承时执行了如下逻辑:

  • 继承结果

父类有 __slot__

父类无 __slot__

子类有 __slot__

子类的的实际范围为父子__slots__ 的并集

子类的的实际范围为子类本身的__slots__

子类无 __slot__

子类__slots__= () ,无法创建新成员,完全遵循父类的规则

子类没有设置 __slots__

  • 可以看到当父类有__slots__而子类没有时(也就是我们期望继承时),子类被约束在父类的规则之下,无法创建新成员,其他情况不受影响,也就达到了我们需要继承父类__slots__的目的

约束范围

需要注意一点,__slots__类对实例属性的约束,而类对象无法通过该属性,约束自己。即为类对象添加新属性,仍然是被允许的。

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年10月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 限制变量范围
  • 提升成员访问性能
  • 继承问题
  • 约束范围
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档