__slots__是一个特殊的类属性,它限制了实例可用属性的集合,从而节省内存并加快对属性的访问。使用__slots__在多个相似对象的情况下尤为重要。
问题的背景:
__slots__的出现与Python对象默认拥有属性字典(__dict__)有关,这虽然方便,但内存开销大。对于具有少量字段的百万个对象,会产生显著的开销。
问题:
普通类的实例可以动态扩展,这很方便,但效率不高。使用__slots__可以限制动态添加新属性,去掉实例属性字典,节省内存并加快访问速度。
解决方案:
在__slots__属性中描述允许的字段列表:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point'对象没有属性'z'
关键特性:
可以创建一个带有__slots__的类的实例,然后添加不在列表中的属性吗?
不可以。尝试添加不在__slots__列表中的属性会引发AttributeError。这对对象的扩展性施加了限制。
可以继承带有__slots__的类并添加新字段吗?
可以,但每个子类必须声明其自己的__slots__。此时,父类和当前类的__slots__会合并。然而,如果在子类中未声明__slots__,子对象将再次拥有__dict__!
__slots__适用于不可变(immutable)类型吗?
可以,但需要实施额外的措施使槽对象保持不可变(例如,通过没有setter的property)。
一个普通的点类:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
优点:
缺点:
相似的类,但使用槽:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
优点:
缺点: