zoukankan      html  css  js  c++  java
  • 第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__的作用

    1. slots 允许开发人员显式地声明限定的数据成员(例如特征属性),禁止未声明的成员动态加入;
    2. 这个 slots 会为已声明的变量保留空间,并阻止自动为每个实例创建 dict 和 __weakref_特殊变量(除非是在 slots 中显式地声明或是在父类中可用)。
    1. 而当继承自一个未定义 slots 的类时,实例的 dictweakref 属性将总是可访问;
    2. 没有 dict 变量,实例就不能给未在 slots 定义中列出的新变量赋值。尝试给一个未列出的变量名赋值将引发 AttributeError。新变量需要动态赋值,就要将 ‘dict’ 加入到 slots 声明的字符串序列中。
    3. 如果未给每个实例设置 weakref 变量,定义了 slots 的类就不支持对其实际的弱引用。如果需要弱引用支持,就要将 ‘weakref’ 加入到 slots 声明的字符串序列中。
    1. 使用__slots__相比使用 dict 方式可以显著地节省空间。 属性查找速度也可得到显著的提升;
    2. slots 声明的作用不只限于定义它的类。在父类中声明的 slots 在其子类中同样可用。不过,子类将会获得 dictweakref 除非它们也定义了 slots (其中应该仅包含对任何 额外 名称的声明位置)。
    3. 非空的 slots 不适用于派生自“可变长度”内置类型例如 int、bytes 和 tuple 的派生类;
    4. __ slots__只能在类体代码中赋值,赋值后:
    1. 不能通过类体外使用“实例名.__ slots__”方式重新赋值,Python会报该属性只读;
    2. 不能在实例方法中和类体外代码中使用“类名.__ slots__” 方式赋值,赋值时不会报错,但__ slots__不起作用,如实例中__dict__会自动创建,如果类体中原来已经定义了__slots__,在实例方法中修改__slots__,可以修改,但Python还是只允许类体中定义的__ slots__中限定的属性添加。
    1. 定义了__ slots__后,如果在代码中定义__ slots__外的实例变量,则会报AttributeError错误;
    2. __ slots__定义以后,在实例方法含构造方法中都不能新定义__ slots__外的其他实例变量。

    四、 三个案例

    1. 源代码如下:
      #案例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__  #没有字典属性
    
    1. 执行截屏:

    本节介绍了特殊变量__slots__的定义和使用以及注意事项,并举例进行了说明,通过介绍可以知道,__slots__相当于是一个实例变量的白名单。

    老猿Python,跟老猿学Python!
    博客地址:https://blog.csdn.net/LaoYuanPython

    请大家多多支持,点赞、评论和加关注!谢谢!

  • 相关阅读:
    【bzoj1036】【ZJOI2008】树的统计
    AE基础(8)PageLayout属性设置和添加元素
    AE基础(7)布局控件与地图控件关联
    UtilityAction扩展
    UtilityAction
    AE基础(6)数据查询与选择
    NavigationAction
    LayerAction
    AE基础(5)鹰眼功能
    AE基础(4)画几何图形
  • 原文地址:https://www.cnblogs.com/LaoYuanPython/p/11166836.html
Copyright © 2011-2022 走看看