TOC

Python __slots__

基本语法

import sys

# 不使用 __slots__
class WithoutSlots:
    def __init__(self, attr1, attr2, attr3, attr4, attr5):
        self.attr1 = attr1
        self.attr2 = attr2
        self.attr3 = attr3
        self.attr4 = attr4
        self.attr5 = attr5

# 使用 __slots__
class WithSlots:
    __slots__ = ['attr1', 'attr2', 'attr3', 'attr4', 'attr5']

    def __init__(self, attr1, attr2, attr3, attr4, attr5):
        self.attr1 = attr1
        self.attr2 = attr2
        self.attr3 = attr3
        self.attr4 = attr4
        self.attr5 = attr5

# 创建对象
obj1 = WithoutSlots(10, 20, 30, 40, 50)
obj2 = WithSlots(10, 20, 30, 40, 50)

# 打印内存使用情况
print(f"Without __slots__: {sys.getsizeof(obj1)} bytes")
print(f"With __slots__: {sys.getsizeof(obj2)} bytes")
# Without __slots__: 48 bytes
# With __slots__: 72 bytes

print(obj1.attr1)  # 10
print(obj1.attr2)  # 20
print(obj1.attr3)  # 30
print(obj1.attr4)  # 40
print(obj1.attr5)  # 50
obj1.attr6 = 60
print(obj1.attr6)  # 60

print(obj1.__dict__)
# {'attr1': 10, 'attr2': 20, 'attr3': 30, 'attr4': 40, 'attr5': 50, 'attr6': 60}

print(obj2.attr1)  # 10
print(obj2.attr2)  # 20
print(obj2.attr3)  # 30
print(obj2.attr4)  # 40
print(obj2.attr5)  # 50
obj2.attr6 = 60  # AttributeError: 'WithSlots' object has no attribute 'attr6'

print(obj2.__dict__) # AttributeError: 'WithSlots' object has no attribute '__dict__'

优势

Python 通过字典 (__dict__) 来储存对象属性,这样更加灵活,但是也会带来一些存储开销与性能开销。
如果只需要固定的属性,可以使用 __slots__ 来优化。

注意:子类会继承父类的 slots 属性,如果希望做拓展,可以在之类中添加新的 slots 属性,例如:

class Parent:
    __slots__ = ['attr1']

    def __init__(self, attr1):
        self.attr1 = attr1

class Child(Parent):
    __slots__ = ['attr2']

    def __init__(self, attr1, attr2):
        super().__init__(attr1)
        self.attr2 = attr2

# 创建子类对象
child = Child(10, 20)
print(child.attr1)  # 10
print(child.attr2)  # 20

参考资料与拓展阅读

  • Slotscheck: 🎰 Ensure your __slots__ are working properly
如果你有魔法,你可以看到一个评论框~