【python进阶】类的__slots__属性

python作为一门动态语言,可以在对象创建后动态的添加属性和方法。

示例1:动态添加属性

class Dog(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

dog = Dog('ahuang', 10)
dog.home = 'China'    # 直接外部定义
print(dog.home)        

示例2:动态添加属性

class Dog(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
def love(self, value):   # 定义外部函数
    self.favorite = value
    print(f"The dog loves {value}")

from types import MethodType
dog.love = MethodType(love, dog)     # 通过MethodType将外部函数绑定到对象上

print(dog.love)   # >
print(dog.favorite)   # 'meat'

动态语言的特性无疑增加了python语言的灵活性,但也带来了风险:暴露的对象可以被用户任意恶意添加属性。而类的__slots__属性提供了一种解决方案:

示例3:定义__slots__属性

class Dog_slot(object):
    __slots__ = ['name', 'age']
    def __init__(self, name, age):
        self.name = name
        self.age = age

dog_slot = Dog_slot('ahuang', 10)
dog_slot.home = 'China'    # 直接报错:AttributeError: 'Dog' object has no attribute 'home'

在上面的Dog类中直接申明了所有的属性,因此无法定义其他的属性(无论是内部定义还是外部绑定!)

除了无法定义新的属性外,在定义__slots__后,还有一个额外的好处:节省内存空间,因为此时对象没有了__dict__属性,而会增加__slots__。因为__slots__是静态的,而非__dict__支持动态添加,因此对象会节省memory。

因此,当事先确定好class的所有attributes时候,建议使用slots来节省memory以及获得更快的attribute access。此外,不应当机械的为了防止创造__slots__之外的新属性作为使用__slots__的原因。

在__slots__的使用,还需要注意如下几点:
(1)父类定义了__slots__, 子类没定义__slots__,则子类会完全继承父类的__slots__以及__slots__中定义的属性。同时会生成__dict__属性,因此仍可以动态添加新的属性;
(2)父类定义了__slots__,子类中定义了新的__slots__,则子类会继承父类的__slots__中涉及的相关属性,而__slots__中只保留新定义的属性;
(3)父类定义了__slots__,子类中定义的__slots__与父类有重复,则作为重复项处理;
(4)如果为多继承关系,且父类的各__slots__(若定义了的话)不一致,则会报错。

【Reference】

  1. 如何理解和使用python里的__slots__?
  2. usage-of-slots

你可能感兴趣的:(python,slots)