第8.20节 Python中限制动态定义实例属性的白名单:__slots__
一、 引言
按照《第7.10节 Python类中的实例变量定义与使用》、《第7.14节Python类中的实例方法解析》中的介绍,当定义了一个类,并且创建了该类的实例后,可以给该实例动态增加任何属性和方法。但实际上,Python中的类可以控制哪些属性可以增加,这个就类似于一个可以动态增加属性的白名单。这个白名单就定义在类的特殊实例变量__slots__中。
二、 slots
__slots__这个特殊变量在object类中是没有定义的,因此如果使用必须在自定义类中单独定义,并且必须是类变量,不能是实例变量。常规定义的语法如下:
slots = (变量名1,变量名2,…)
slots = [变量名1,变量名2,…]
…
由于__slots__是类变量,因此最好放在类体代码中定义,其中的变量数可以是1到多个。使用第一种方式,当变量是1个时,__slots__自身是字符串类型,当变量是多个时,它是元组类型;使用第二种方式,类变量__slots__类型为列表。实际上__slots__可赋值为字符串、可迭代对象或由实例使用的变量名构成的字符串序列,任何非字符串可迭代对象都可以被赋值给 slots。映射也可以被使用,在此不展开介绍每种赋值方式。
三、 __slots__的作用
- slots 允许开发人员显式地声明限定的数据成员(例如特征属性),禁止未声明的成员动态加入;
- 这个 slots 会为已声明的变量保留空间,并阻止自动为每个实例创建 dict 和 __weakref_特殊变量(除非是在 slots 中显式地声明或是在父类中可用)。
- 而当继承自一个未定义 slots 的类时,实例的 dict 和 weakref 属性将总是可访问;
- 没有 dict 变量,实例就不能给未在 slots 定义中列出的新变量赋值。尝试给一个未列出的变量名赋值将引发 AttributeError。新变量需要动态赋值,就要将 ‘dict’ 加入到 slots 声明的字符串序列中。
- 如果未给每个实例设置 weakref 变量,定义了 slots 的类就不支持对其实际的弱引用。如果需要弱引用支持,就要将 ‘weakref’ 加入到 slots 声明的字符串序列中。
- 使用__slots__相比使用 dict 方式可以显著地节省空间。 属性查找速度也可得到显著的提升;
- slots 声明的作用不只限于定义它的类。在父类中声明的 slots 在其子类中同样可用。不过,子类将会获得 dict 和 weakref 除非它们也定义了 slots (其中应该仅包含对任何 额外 名称的声明位置)。
- 非空的 slots 不适用于派生自“可变长度”内置类型例如 int、bytes 和 tuple 的派生类;
- __ slots__只能在类体代码中赋值,赋值后:
- 不能通过类体外使用“实例名.__ slots__”方式重新赋值,Python会报该属性只读;
- 不能在实例方法中和类体外代码中使用“类名.__ slots__” 方式赋值,赋值时不会报错,但__ slots__不起作用,如实例中__dict__会自动创建,如果类体中原来已经定义了__slots__,在实例方法中修改__slots__,可以修改,但Python还是只允许类体中定义的__ slots__中限定的属性添加。
- 定义了__ slots__后,如果在代码中定义__ slots__外的实例变量,则会报AttributeError错误;
- __ slots__定义以后,在实例方法含构造方法中都不能新定义__ slots__外的其他实例变量。
四、 三个案例
- 源代码如下:
#案例1:#使用实例方法来定义类变量Vehicle.__slots__没有作用
class Vehicle():
def __init__(self,power):
self.power = power
Vehicle.__slots__ = ['power']
v=Vehicle('人力')
v.wheelcount=4 #加一个实例变量不会拦截
v.__dict__ #服务字典中的自定义属性成功
#案例2:#使用类体来定义类变量__slots__可以正常发挥作用
class Vehicle():
__slots__ = ['power']
def __init__(self,power):
self.power = power
v=Vehicle('人力')
v.wheelcount=4 #加一个实例变量会拦截
v.__dict__ #没有字典属性
#案例3:#定义类变量__slots__后在类体外修改,可以修改但修改不起作用
class Vehicle():
__slots__ = ['power','weight']
def __init__(self,power):
self.power = power
v=Vehicle('人力')
Vehicle.__slots__ = ['wheelcount','oilcost']
Vehicle.__slots__ #显示赋值被修改
v.wheelcount=4 #加一个实例变量会拦截
v.__dict__ #没有字典属性
- 执行截屏:

本节介绍了特殊变量__slots__的定义和使用以及注意事项,并举例进行了说明,通过介绍可以知道,__slots__相当于是一个实例变量的白名单。
老猿Python,跟老猿学Python!
博客地址:https://blog.csdn.net/LaoYuanPython
请大家多多支持,点赞、评论和加关注!谢谢!
第8.20节 Python中限制动态定义实例属性的白名单:__slots__的更多相关文章
- 第8.28节 Python中使用__setattr__定义实例变量和实例方法
一. 引言 根据前面章节介绍的内容,我们知道实例变量.实例方法的定义可以通过以下方法进行: 在类体中直接定义实例变量.实例方法: 在实例方法中定义实例变量.实例方法: 在类体外调用方使用赋值语句赋值定 ...
- 第11.20节 Python 中正则表达式的扩展功能:后视断言、后视取反
一. 引言 在<第11.19节 Python 中正则表达式的扩展功能:前视断言和前视取反>中老猿介绍了前视断言和前视取反,与二者对应的还有后视断言和后视取反. 二. (?<=-)后视 ...
- 第8.32节 Python中重写__delattr__方法捕获属性删除
一. 引言 上节介绍了__delattr__方法在Python清除实例属性时被捕获执行,本节结合例子介绍重写__delattr__方法,并说明__delattr__方法执行的触发逻辑. 二. 重写__ ...
- Python 中使用动态创建类属性的机制实现接口之后的依赖
我们在自动化测试中经常会需要关联用例处理,需要动态类属性: 推荐使用第二种方法: 创建:setattr() 获取:getattr() 两种,如何创建 类属性 loan_id # 第一种,创建 # 类名 ...
- 第8.12节 Python类中使用__dict__定义实例变量和方法
上节介绍了使用实例的__dict__查看实例的自定义属性,其实还可以直接使用__dict__定义实例变量和实例方法. 一. 使用__dict__定义实例变量 语法: 对象名. dict[属性名] = ...
- 第14.8节 Python中使用BeautifulSoup加载HTML报文
一. 引言 BeautifulSoup是一个三方模块bs4中提供的进行HTML解析的类,可以认为是一个HTML解析工具箱,对HTML报文中的标签具有比较好的容错识别功能.阅读本节需要了解html相关的 ...
- Python中的动态类
Python中的动态类 有这样一个需求,我有SegmentReader.PostagReader.ConllReader这三个Reader,他们都继承于一个Reader类.在程序运行中,由用户通过se ...
- 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类
第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一. 引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...
- 第7.15节 Python中classmethod定义的类方法详解
第7.15节 Python中classmethod定义的类方法详解 类中的方法,除了实例方法外,还有两种方法,分别是类方法和静态方法.本节介绍类方法的定义和使用. 一. 类方法的定义 在类中定 ...
随机推荐
- 在pgsql库用触发器自动触发PostgreSQL的存储过程,实现插入。
需求:在对表A 执行 insert操作时,筛选符合条件的数据 insert到表B中,编写为存储过程(postgreSQL数据库) [筛选条件]:1. dd !="A" 或是 dd为 ...
- Pycharm激活码无偿分享,2020年最新Pycharm永久激活码!
2020年10月7日08:04:34更新的Pycharm激活码,还热乎着呢,速用~ 如果下边的这个Pycharm激活码过期失效了的话,大家可以关注我的微信公众号:Python联盟,然后回复" ...
- 记载idea创建spring-boot项目时“Spring Initalizr Error”的问题处理
- Spark Standalone模式 高可用部署
本文使用Spark的版本为:spark-2.4.0-bin-hadoop2.7.tgz. spark的集群采用3台机器进行搭建,机器分别是server01,server02,server03. 其 ...
- 面试题:能谈谈Date、Datetime、Time、Timestamp、year的区别吗?
一. 推荐阅读 首发地址:https://mp.weixin.qq.com/s/9zKX86P4kzlKla6-NyS3EA 使用推荐阅读,有更好的阅读体验 二.准备 如果面试官问你:了解 date. ...
- springMVC请求调用过程
在传统的MVC模式中,Tomcat通过读取web.XML配置文件来获取servlet和访问路径的映射关系,这样在访问tomcat就能将请求转发给对应的servlet进行处理. 自定义的servlet是 ...
- 采用“传统”方式获取当前HttpContext
我们知道"依赖注入"已经成为了.NET Core的基本编程模式,表示当前请求上下文的HttpContext可以通过注入的IHttpContextAccessor服务来提取.有时候我 ...
- binary hacks读数笔记(nm命令)
nm命令(names):输出包含三个部分:1 符号值.默认显示十六进制,也可以指定: 2 符号类型.小写表示是本地符号,大写表示全局符号(external); 3 符号名称. 例如:nm Simple ...
- Java初始化静态变量的时间顺序
1. 开始吧! 今天,我们来探讨交流下静态变量初始化过程.Java虚拟机在类加载期间也同样遵循这个过程. 2. 初始化过程 在较高的层次上,JVM执行以下步骤: 首先,加载并链接类.然后,这个过程的& ...
- ceph的df容量显示计算
显示数据 [root@lab201 ~]# ceph df GLOBAL: SIZE AVAIL RAW USED %RAW USED 1092T 404T 688T 63.01% POOLS: NA ...