编程后端Python开发者

什么是Python类中的__slots__,它们的用途是什么,它们的限制是什么?

用 Hintsage AI 助手通过面试

答案。

__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'

关键特性:

  • 通过缺乏默认的__dict__和__weakref__节省内存。
  • 定义严格的允许字段集合。
  • 通过预分配的槽加快对属性的访问(无需在字典中查找)。

诱惑性问题。

可以创建一个带有__slots__的类的实例,然后添加不在列表中的属性吗?

不可以。尝试添加不在__slots__列表中的属性会引发AttributeError。这对对象的扩展性施加了限制。

可以继承带有__slots__的类并添加新字段吗?

可以,但每个子类必须声明其自己的__slots__。此时,父类和当前类的__slots__会合并。然而,如果在子类中未声明__slots__,子对象将再次拥有__dict__!

__slots__适用于不可变(immutable)类型吗?

可以,但需要实施额外的措施使槽对象保持不可变(例如,通过没有setter的property)。

常见错误和反模式

  • 不在子类中声明__slots__,导致内存效率下降。
  • 希望在存在多重继承的情况下正常工作__slots__ — 可能会出现冲突和错误。
  • 尝试使用标准方法序列化具有槽的对象有时会困难(例如,pickle需要__dict__)。

生活中的示例

消极案例

一个普通的点类:

class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]

优点:

  • 灵活——可以添加任意属性。
  • 对初学者友好。

缺点:

  • 任务管理器显示内存使用显著增加(最高可达+20-30%)。

积极案例

相似的类,但使用槽:

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)]

优点:

  • 在百万个对象中节省高达30%的内存。
  • 更快地访问字段。

缺点:

  • 对象变得不灵活:无法随意添加新属性。