When your application creates thousands or millions of small objects (like game entities, data points, or cache entries), memory usage can explode due to Python's per-instance dictionary overhead. Using __slots__ restricts objects to a fixed set of attributes, dramatically reducing memory consumption.

__slots__ is a class-level attribute that restricts instance attributes to a fixed set, providing memory savings and faster attribute access. By defining __slots__, Python does not create a __dict__ for each instance.

Defining __slots__

person1
slots_definition.py
Replay: real traced execution (multi-file project)
"""Basic __slots__ definition"""

# Without __slots__
print("Without __slots__:")

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

person1 = PersonNoSlots("Alice", 30)
print(f"Name: {person1.name}, Age: {person1.age}")
print(f"Has __dict__: {hasattr(person1, '__dict__')}")
print(f"__dict__: {person1.__dict__}")

# Can add dynamic attributes
person1.email = "alice@example.com"
print(f"Added email: {person1.email}")

# With __slots__
print("\nWith __slots__:")

class PersonWithSlots:
    __slots__ = ['name', 'age']

    def __init__(self, name, age):
        self.name = name
        self.age = age

person2 = PersonWithSlots("Bob", 25)
print(f"Name: {person2.name}, Age: {person2.age}")
print(f"Has __dict__: {hasattr(person2, '__dict__')}")

# Cannot add dynamic attributes
try:
    person2.email = "bob@example.com"
except AttributeError as e:
    print(f"Error adding email: {e}")

# Tuple __slots__
print("\nTuple __slots__:")

class Point:
    __slots__ = ('x', 'y')  # Can use tuple instead of list

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(10, 20)
print(f"Point: {p}")
print(f"x={p.x}, y={p.y}")

# Multiple attributes
print("\nMultiple attributes:")

class User:
    __slots__ = ['user_id', 'username', 'email', 'created_at']

    def __init__(self, user_id, username, email, created_at):
        self.user_id = user_id
        self.username = username
        self.email = email
        self.created_at = created_at

    def __repr__(self):
        return f"User(id={self.user_id}, username='{self.username}')"

user = User(1, "alice", "alice@example.com", "2024-01-01")
print(f"User: {user}")

# Read-only slots
print("\nRead-only slots:")

class Config:
    __slots__ = ['_host', '_port']

    def __init__(self, host, port):
        self._host = host
        self._port = port

    @property
    def host(self):
        return self._host

    @property
    def port(self):
        return self._port

config = Config("localhost", 8080)
print(f"Config: {config.host}:{config.port}")

# Cannot modify (no setter)
try:
    config.host = "0.0.0.0"
except AttributeError as e:
    print(f"Error: {e}")

# Empty __slots__
print("\nEmpty __slots__:")

class Immutable:
    __slots__ = []  # No instance attributes allowed

    VALUE = 42  # Class attribute is OK

im = Immutable()
print(f"Class value: {im.VALUE}")

try:
    im.x = 10
except AttributeError as e:
    print(f"Error: {e}")

# Checking __slots__
print("\nChecking __slots__:")

class Example:
    __slots__ = ['a', 'b', 'c']

print(f"__slots__: {Example.__slots__}")
print(f"Allowed attributes: {', '.join(Example.__slots__)}")

# Practical example
print("\nPractical example:")

class Vector2D:
    __slots__ = ['x', 'y']

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vector2D({self.x}, {self.y})"

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
v3 = v1 + v2

print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v3 = v1 + v2 = {v3}")
print(f"v1 magnitude = {v1.magnitude()}")

"""Basic __slots__ definition"""

# Without __slots__
print("Without __slots__:")

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

person1 = PersonNoSlots("Bob", 25)
print(f"Name: {person1.name}, Age: {person1.age}")
print(f"Has __dict__: {hasattr(person1, '__dict__')}")
print(f"__dict__: {person1.__dict__}")

# Can add dynamic attributes
person1.email = "alice@example.com"
print(f"Added email: {person1.email}")

# With __slots__
print("\nWith __slots__:")

class PersonWithSlots:
    __slots__ = ['name', 'age']

    def __init__(self, name, age):
        self.name = name
        self.age = age

person2 = PersonWithSlots("Bob", 25)
print(f"Name: {person2.name}, Age: {person2.age}")
print(f"Has __dict__: {hasattr(person2, '__dict__')}")

# Cannot add dynamic attributes
try:
    person2.email = "bob@example.com"
except AttributeError as e:
    print(f"Error adding email: {e}")

# Tuple __slots__
print("\nTuple __slots__:")

class Point:
    __slots__ = ('x', 'y')  # Can use tuple instead of list

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(10, 20)
print(f"Point: {p}")
print(f"x={p.x}, y={p.y}")

# Multiple attributes
print("\nMultiple attributes:")

class User:
    __slots__ = ['user_id', 'username', 'email', 'created_at']

    def __init__(self, user_id, username, email, created_at):
        self.user_id = user_id
        self.username = username
        self.email = email
        self.created_at = created_at

    def __repr__(self):
        return f"User(id={self.user_id}, username='{self.username}')"

user = User(1, "alice", "alice@example.com", "2024-01-01")
print(f"User: {user}")

# Read-only slots
print("\nRead-only slots:")

class Config:
    __slots__ = ['_host', '_port']

    def __init__(self, host, port):
        self._host = host
        self._port = port

    @property
    def host(self):
        return self._host

    @property
    def port(self):
        return self._port

config = Config("localhost", 8080)
print(f"Config: {config.host}:{config.port}")

# Cannot modify (no setter)
try:
    config.host = "0.0.0.0"
except AttributeError as e:
    print(f"Error: {e}")

# Empty __slots__
print("\nEmpty __slots__:")

class Immutable:
    __slots__ = []  # No instance attributes allowed

    VALUE = 42  # Class attribute is OK

im = Immutable()
print(f"Class value: {im.VALUE}")

try:
    im.x = 10
except AttributeError as e:
    print(f"Error: {e}")

# Checking __slots__
print("\nChecking __slots__:")

class Example:
    __slots__ = ['a', 'b', 'c']

print(f"__slots__: {Example.__slots__}")
print(f"Allowed attributes: {', '.join(Example.__slots__)}")

# Practical example
print("\nPractical example:")

class Vector2D:
    __slots__ = ['x', 'y']

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vector2D({self.x}, {self.y})"

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
v3 = v1 + v2

print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v3 = v1 + v2 = {v3}")
print(f"v1 magnitude = {v1.magnitude()}")

"""Basic __slots__ definition"""

# Without __slots__
print("Without __slots__:")

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

person1 = PersonNoSlots("Carol", 45)
print(f"Name: {person1.name}, Age: {person1.age}")
print(f"Has __dict__: {hasattr(person1, '__dict__')}")
print(f"__dict__: {person1.__dict__}")

# Can add dynamic attributes
person1.email = "alice@example.com"
print(f"Added email: {person1.email}")

# With __slots__
print("\nWith __slots__:")

class PersonWithSlots:
    __slots__ = ['name', 'age']

    def __init__(self, name, age):
        self.name = name
        self.age = age

person2 = PersonWithSlots("Bob", 25)
print(f"Name: {person2.name}, Age: {person2.age}")
print(f"Has __dict__: {hasattr(person2, '__dict__')}")

# Cannot add dynamic attributes
try:
    person2.email = "bob@example.com"
except AttributeError as e:
    print(f"Error adding email: {e}")

# Tuple __slots__
print("\nTuple __slots__:")

class Point:
    __slots__ = ('x', 'y')  # Can use tuple instead of list

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(10, 20)
print(f"Point: {p}")
print(f"x={p.x}, y={p.y}")

# Multiple attributes
print("\nMultiple attributes:")

class User:
    __slots__ = ['user_id', 'username', 'email', 'created_at']

    def __init__(self, user_id, username, email, created_at):
        self.user_id = user_id
        self.username = username
        self.email = email
        self.created_at = created_at

    def __repr__(self):
        return f"User(id={self.user_id}, username='{self.username}')"

user = User(1, "alice", "alice@example.com", "2024-01-01")
print(f"User: {user}")

# Read-only slots
print("\nRead-only slots:")

class Config:
    __slots__ = ['_host', '_port']

    def __init__(self, host, port):
        self._host = host
        self._port = port

    @property
    def host(self):
        return self._host

    @property
    def port(self):
        return self._port

config = Config("localhost", 8080)
print(f"Config: {config.host}:{config.port}")

# Cannot modify (no setter)
try:
    config.host = "0.0.0.0"
except AttributeError as e:
    print(f"Error: {e}")

# Empty __slots__
print("\nEmpty __slots__:")

class Immutable:
    __slots__ = []  # No instance attributes allowed

    VALUE = 42  # Class attribute is OK

im = Immutable()
print(f"Class value: {im.VALUE}")

try:
    im.x = 10
except AttributeError as e:
    print(f"Error: {e}")

# Checking __slots__
print("\nChecking __slots__:")

class Example:
    __slots__ = ['a', 'b', 'c']

print(f"__slots__: {Example.__slots__}")
print(f"Allowed attributes: {', '.join(Example.__slots__)}")

# Practical example
print("\nPractical example:")

class Vector2D:
    __slots__ = ['x', 'y']

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vector2D({self.x}, {self.y})"

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
v3 = v1 + v2

print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v3 = v1 + v2 = {v3}")
print(f"v1 magnitude = {v1.magnitude()}")

  1. """Basic __slots__ definition"""

    1"""Basic __slots__ definition"""23# Without __slots__4print("Without __slots__:")56class PersonNoSlots:7    def __init__(self, name, age):8        self.name = name9        self.age = age1011person1 = PersonNoSlots("Alice", 30)  #@person1=PersonNoSlots("Bob", 25), PersonNoSlots("Carol", 45)12print(f"Name: {person1.name}, Age: {person1.age}")
    outputWithout __slots__:
  2. self.name ← Alice, self.age ← 30

    6class PersonNoSlots:7    def __init__(self⟨PersonNoSlots A⟩, nameAlice, age30):8        self.name→ Alice = nameAlice9        self.age→ 30 = age30
  3. person1 ← ⟨PersonNoSlots A⟩, person1.email ← alice@example.com

    11person1→ ⟨PersonNoSlots A⟩ = PersonNoSlots("Alice", 30)  #@person1=PersonNoSlots("Bob", 25), PersonNoSlots("Carol", 45)12print(f"Name: {person1.nameAlice}, Age: {person1.age30}")13print(f"Has __dict__: {hasattr(person1⟨PersonNoSlots A⟩, '__dict__')}")14print(f"__dict__: {person1.__dict__{'name': 'Alice', 'age': 30}}")1516# Can add dynamic attributes17person1.email→ alice@example.com = "alice@example.com"18print(f"Added email: {person1.emailalice@example.com}")1920# With __slots__21print("\nWith __slots__:")2223class PersonWithSlots:24    __slots__ = ['name', 'age']25    26    def __init__(self, name, age):27        self.name = name28        self.age = age2930person2 = PersonWithSlots("Bob", 25)31print(f"Name: {person2.name}, Age: {person2.age}")
    outputName: Alice, Age: 30
    Has __dict__: True
    __dict__: {'name': 'Alice', 'age': 30}
    Added email: alice@example.com
    
    With __slots__:
  4. self.name ← Bob, self.age ← 25

    26def __init__(self⟨PersonWithSlots B⟩, nameBob, age25):27    self.name→ Bob = nameBob28    self.age→ 25 = age25
  5. person2 ← ⟨PersonWithSlots B⟩

    30person2→ ⟨PersonWithSlots B⟩ = PersonWithSlots("Bob", 25)31print(f"Name: {person2.nameBob}, Age: {person2.age25}")32print(f"Has __dict__: {hasattr(person2⟨PersonWithSlots B⟩, '__dict__')}")
    outputName: Bob, Age: 25
    Has __dict__: False
  6. except AttributeError as e:

    36    person2.email = "bob@example.com"37except AttributeError as e:38    print(f"Error adding email: {e'PersonWithSlots' object has no attribute 'email'}")
    outputError adding email: 'PersonWithSlots' object has no attribute 'email'
  7. print(" Tuple __slots__:")

    40# Tuple __slots__41print("\nTuple __slots__:")4243class Point:44    __slots__ = ('x', 'y')  # Can use tuple instead of list45    46    def __init__(self, x, y):47        self.x = x48        self.y = y49    50    def __repr__(self):51        return f"Point({self.x}, {self.y})"5253p = Point(10, 20)54print(f"Point: {p}")
    output
    Tuple __slots__:
  8. self.x ← 10, self.y ← 20

    46def __init__(self(empty), x10, y20):47    self.x→ 10 = x1048    self.y→ 20 = y20
  9. p ← Point(10, 20)

    53p→ Point(10, 20) = Point(10, 20)54print(f"Point: {pPoint(10, 20)}")55print(f"x={p.x10}, y={p.y20}")5657# Multiple attributes58print("\nMultiple attributes:")5960class User:61    __slots__ = ['user_id', 'username', 'email', 'created_at']62    63    def __init__(self, user_id, username, email, created_at):64        self.user_id = user_id65        self.username = username66        self.email = email67        self.created_at = created_at68    69    def __repr__(self):70        return f"User(id={self.user_id}, username='{self.username}')"7172user = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {user}")
    outputPoint: Point(10, 20)
    x=10, y=20
    
    Multiple attributes:
  10. self.user_id ← 1, self.username ← alice, self.email ← alice@example.com

    63def __init__(self(empty), user_id1, usernamealice, emailalice@example.com, created_at2024-01-01):64    self.user_id→ 1 = user_id165    self.username→ alice = usernamealice66    self.email→ alice@example.com = emailalice@example.com67    self.created_at→ 2024-01-01 = created_at2024-01-01
  11. user ← User(id=1, username='alice')

    72user→ User(id=1, username='alice') = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {userUser(id=1, username='alice')}")7475# Read-only slots76print("\nRead-only slots:")7778class Config:79    __slots__ = ['_host', '_port']80    81    def __init__(self, host, port):82        self._host = host83        self._port = port84    85    @property86    def host(self):87        return self._host88    89    @property90    def port(self):91        return self._port9293config = Config("localhost", 8080)94print(f"Config: {config.host}:{config.port}")
    outputUser: User(id=1, username='alice')
    
    Read-only slots:
  12. self._host ← localhost, self._port ← 8080

    81def __init__(self⟨Config C⟩, hostlocalhost, port8080):82    self._host→ localhost = hostlocalhost83    self._port→ 8080 = port8080
  13. config ← ⟨Config C⟩

    93config→ ⟨Config C⟩ = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
  14. def host(self):

    85@property86def host(self⟨Config C⟩):87    return self._hostlocalhost
  15. def port(self):

    89@property90def port(self⟨Config C⟩):91    return self._port8080
  16. print(f"Config: {config.host}:{config.port}")

    93config = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
    outputConfig: localhost:8080
  17. except AttributeError as e:

    98    config.host = "0.0.0.0"99except AttributeError as e:100    print(f"Error: {eproperty 'host' of 'Config' object has no setter}")
    outputError: property 'host' of 'Config' object has no setter
  18. VALUE ← (empty), im ← ⟨Immutable D⟩

    102# Empty __slots__103print("\nEmpty __slots__:")104105class Immutable:106    __slots__ = []  # No instance attributes allowed107    108    VALUE→ (empty) = 42  # Class attribute is OK109110im→ ⟨Immutable D⟩ = Immutable()111print(f"Class value: {im.VALUE42}")
    output
    Empty __slots__:
    Class value: 42
  19. except AttributeError as e:

    114    im.x = 10115except AttributeError as e:116    print(f"Error: {e'Immutable' object has no attribute 'x'}")
    outputError: 'Immutable' object has no attribute 'x'
  20. print(f"__slots__: {Example.__slots__}")

    118# Checking __slots__119print("\nChecking __slots__:")120121class Example:122    __slots__ = ['a', 'b', 'c']123124print(f"__slots__: {Example.__slots__['a', 'b', 'c']}")125print(f"Allowed attributes: {', '.join(Example.__slots__['a', 'b', 'c'])}")126127# Practical example128print("\nPractical example:")129130class Vector2D:131    __slots__ = ['x', 'y']132    133    def __init__(self, x=0, y=0):134        self.x = x135        self.y = y136    137    def __repr__(self):138        return f"Vector2D({self.x}, {self.y})"139    140    def __add__(self, other):141        return Vector2D(self.x + other.x, self.y + other.y)142    143    def magnitude(self):144        return (self.x ** 2 + self.y ** 2) ** 0.5145146v1 = Vector2D(3, 4)147v2 = Vector2D(1, 2)
    output
    Checking __slots__:
    __slots__: ['a', 'b', 'c']
    Allowed attributes: a, b, c
    
    Practical example:
  21. self.x ← 3, self.y ← 4

    pass 1 of 3
    133def __init__(self(empty), x3=0, y4=0):134    self.x→ 3 = x3135    self.y→ 4 = y4
    All 3 passes — pass 1 is the card above
    passxyself.xself.y
    13434
    21212
    34646
  22. v1 ← Vector2D(3, 4)

    146v1→ Vector2D(3, 4) = Vector2D(3, 4)147v2 = Vector2D(1, 2)148v3 = v1 + v2
  23. v2 ← Vector2D(1, 2)

    146v1 = Vector2D(3, 4)147v2→ Vector2D(1, 2) = Vector2D(1, 2)148v3 = v1Vector2D(3, 4) + v2Vector2D(1, 2)
  24. def __add__(self, other):

    140def __add__(selfVector2D(3, 4), otherVector2D(1, 2)):141    return Vector2D(self.x3 + other.x1, self.y4 + other.y2)
  25. v3 ← Vector2D(4, 6)

    147v2 = Vector2D(1, 2)148v3→ Vector2D(4, 6) = v1Vector2D(3, 4) + v2Vector2D(1, 2)149150print(f"v1 = {v1Vector2D(3, 4)}")151print(f"v2 = {v2Vector2D(1, 2)}")152print(f"v3 = v1 + v2 = {v3Vector2D(4, 6)}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 = Vector2D(3, 4)
    v2 = Vector2D(1, 2)
    v3 = v1 + v2 = Vector2D(4, 6)
  26. def magnitude(self):

    143def magnitude(selfVector2D(3, 4)):144    return (self.x3 ** 2 + self.y4 ** 2) ** 0.5
  27. print(f"v1 magnitude = {v1.magnitude()}")

    152print(f"v3 = v1 + v2 = {v3}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 magnitude = 5.0
  1. """Basic __slots__ definition"""

    1"""Basic __slots__ definition"""23# Without __slots__4print("Without __slots__:")56class PersonNoSlots:7    def __init__(self, name, age):8        self.name = name9        self.age = age1011person1 = PersonNoSlots("Bob", 25)12print(f"Name: {person1.name}, Age: {person1.age}")
    outputWithout __slots__:
  2. self.name ← Bob, self.age ← 25

    6class PersonNoSlots:7    def __init__(self⟨PersonNoSlots A⟩, nameBob, age25):8        self.name→ Bob = nameBob9        self.age→ 25 = age25
  3. person1 ← ⟨PersonNoSlots A⟩, person1.email ← alice@example.com

    11person1→ ⟨PersonNoSlots A⟩ = PersonNoSlots("Bob", 25)12print(f"Name: {person1.nameBob}, Age: {person1.age25}")13print(f"Has __dict__: {hasattr(person1⟨PersonNoSlots A⟩, '__dict__')}")14print(f"__dict__: {person1.__dict__{'name': 'Bob', 'age': 25}}")1516# Can add dynamic attributes17person1.email→ alice@example.com = "alice@example.com"18print(f"Added email: {person1.emailalice@example.com}")1920# With __slots__21print("\nWith __slots__:")2223class PersonWithSlots:24    __slots__ = ['name', 'age']25    26    def __init__(self, name, age):27        self.name = name28        self.age = age2930person2 = PersonWithSlots("Bob", 25)31print(f"Name: {person2.name}, Age: {person2.age}")
    outputName: Bob, Age: 25
    Has __dict__: True
    __dict__: {'name': 'Bob', 'age': 25}
    Added email: alice@example.com
    
    With __slots__:
  4. self.name ← Bob, self.age ← 25

    26def __init__(self⟨PersonWithSlots B⟩, nameBob, age25):27    self.name→ Bob = nameBob28    self.age→ 25 = age25
  5. person2 ← ⟨PersonWithSlots B⟩

    30person2→ ⟨PersonWithSlots B⟩ = PersonWithSlots("Bob", 25)31print(f"Name: {person2.nameBob}, Age: {person2.age25}")32print(f"Has __dict__: {hasattr(person2⟨PersonWithSlots B⟩, '__dict__')}")
    outputName: Bob, Age: 25
    Has __dict__: False
  6. except AttributeError as e:

    36    person2.email = "bob@example.com"37except AttributeError as e:38    print(f"Error adding email: {e'PersonWithSlots' object has no attribute 'email'}")
    outputError adding email: 'PersonWithSlots' object has no attribute 'email'
  7. print(" Tuple __slots__:")

    40# Tuple __slots__41print("\nTuple __slots__:")4243class Point:44    __slots__ = ('x', 'y')  # Can use tuple instead of list45    46    def __init__(self, x, y):47        self.x = x48        self.y = y49    50    def __repr__(self):51        return f"Point({self.x}, {self.y})"5253p = Point(10, 20)54print(f"Point: {p}")
    output
    Tuple __slots__:
  8. self.x ← 10, self.y ← 20

    46def __init__(self(empty), x10, y20):47    self.x→ 10 = x1048    self.y→ 20 = y20
  9. p ← Point(10, 20)

    53p→ Point(10, 20) = Point(10, 20)54print(f"Point: {pPoint(10, 20)}")55print(f"x={p.x10}, y={p.y20}")5657# Multiple attributes58print("\nMultiple attributes:")5960class User:61    __slots__ = ['user_id', 'username', 'email', 'created_at']62    63    def __init__(self, user_id, username, email, created_at):64        self.user_id = user_id65        self.username = username66        self.email = email67        self.created_at = created_at68    69    def __repr__(self):70        return f"User(id={self.user_id}, username='{self.username}')"7172user = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {user}")
    outputPoint: Point(10, 20)
    x=10, y=20
    
    Multiple attributes:
  10. self.user_id ← 1, self.username ← alice, self.email ← alice@example.com

    63def __init__(self(empty), user_id1, usernamealice, emailalice@example.com, created_at2024-01-01):64    self.user_id→ 1 = user_id165    self.username→ alice = usernamealice66    self.email→ alice@example.com = emailalice@example.com67    self.created_at→ 2024-01-01 = created_at2024-01-01
  11. user ← User(id=1, username='alice')

    72user→ User(id=1, username='alice') = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {userUser(id=1, username='alice')}")7475# Read-only slots76print("\nRead-only slots:")7778class Config:79    __slots__ = ['_host', '_port']80    81    def __init__(self, host, port):82        self._host = host83        self._port = port84    85    @property86    def host(self):87        return self._host88    89    @property90    def port(self):91        return self._port9293config = Config("localhost", 8080)94print(f"Config: {config.host}:{config.port}")
    outputUser: User(id=1, username='alice')
    
    Read-only slots:
  12. self._host ← localhost, self._port ← 8080

    81def __init__(self⟨Config C⟩, hostlocalhost, port8080):82    self._host→ localhost = hostlocalhost83    self._port→ 8080 = port8080
  13. config ← ⟨Config C⟩

    93config→ ⟨Config C⟩ = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
  14. def host(self):

    85@property86def host(self⟨Config C⟩):87    return self._hostlocalhost
  15. def port(self):

    89@property90def port(self⟨Config C⟩):91    return self._port8080
  16. print(f"Config: {config.host}:{config.port}")

    93config = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
    outputConfig: localhost:8080
  17. except AttributeError as e:

    98    config.host = "0.0.0.0"99except AttributeError as e:100    print(f"Error: {eproperty 'host' of 'Config' object has no setter}")
    outputError: property 'host' of 'Config' object has no setter
  18. VALUE ← (empty), im ← ⟨Immutable D⟩

    102# Empty __slots__103print("\nEmpty __slots__:")104105class Immutable:106    __slots__ = []  # No instance attributes allowed107    108    VALUE→ (empty) = 42  # Class attribute is OK109110im→ ⟨Immutable D⟩ = Immutable()111print(f"Class value: {im.VALUE42}")
    output
    Empty __slots__:
    Class value: 42
  19. except AttributeError as e:

    114    im.x = 10115except AttributeError as e:116    print(f"Error: {e'Immutable' object has no attribute 'x'}")
    outputError: 'Immutable' object has no attribute 'x'
  20. print(f"__slots__: {Example.__slots__}")

    118# Checking __slots__119print("\nChecking __slots__:")120121class Example:122    __slots__ = ['a', 'b', 'c']123124print(f"__slots__: {Example.__slots__['a', 'b', 'c']}")125print(f"Allowed attributes: {', '.join(Example.__slots__['a', 'b', 'c'])}")126127# Practical example128print("\nPractical example:")129130class Vector2D:131    __slots__ = ['x', 'y']132    133    def __init__(self, x=0, y=0):134        self.x = x135        self.y = y136    137    def __repr__(self):138        return f"Vector2D({self.x}, {self.y})"139    140    def __add__(self, other):141        return Vector2D(self.x + other.x, self.y + other.y)142    143    def magnitude(self):144        return (self.x ** 2 + self.y ** 2) ** 0.5145146v1 = Vector2D(3, 4)147v2 = Vector2D(1, 2)
    output
    Checking __slots__:
    __slots__: ['a', 'b', 'c']
    Allowed attributes: a, b, c
    
    Practical example:
  21. self.x ← 3, self.y ← 4

    pass 1 of 3
    133def __init__(self(empty), x3=0, y4=0):134    self.x→ 3 = x3135    self.y→ 4 = y4
    All 3 passes — pass 1 is the card above
    passxyself.xself.y
    13434
    21212
    34646
  22. v1 ← Vector2D(3, 4)

    146v1→ Vector2D(3, 4) = Vector2D(3, 4)147v2 = Vector2D(1, 2)148v3 = v1 + v2
  23. v2 ← Vector2D(1, 2)

    146v1 = Vector2D(3, 4)147v2→ Vector2D(1, 2) = Vector2D(1, 2)148v3 = v1Vector2D(3, 4) + v2Vector2D(1, 2)
  24. def __add__(self, other):

    140def __add__(selfVector2D(3, 4), otherVector2D(1, 2)):141    return Vector2D(self.x3 + other.x1, self.y4 + other.y2)
  25. v3 ← Vector2D(4, 6)

    147v2 = Vector2D(1, 2)148v3→ Vector2D(4, 6) = v1Vector2D(3, 4) + v2Vector2D(1, 2)149150print(f"v1 = {v1Vector2D(3, 4)}")151print(f"v2 = {v2Vector2D(1, 2)}")152print(f"v3 = v1 + v2 = {v3Vector2D(4, 6)}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 = Vector2D(3, 4)
    v2 = Vector2D(1, 2)
    v3 = v1 + v2 = Vector2D(4, 6)
  26. def magnitude(self):

    143def magnitude(selfVector2D(3, 4)):144    return (self.x3 ** 2 + self.y4 ** 2) ** 0.5
  27. print(f"v1 magnitude = {v1.magnitude()}")

    152print(f"v3 = v1 + v2 = {v3}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 magnitude = 5.0
  1. """Basic __slots__ definition"""

    1"""Basic __slots__ definition"""23# Without __slots__4print("Without __slots__:")56class PersonNoSlots:7    def __init__(self, name, age):8        self.name = name9        self.age = age1011person1 = PersonNoSlots("Carol", 45)12print(f"Name: {person1.name}, Age: {person1.age}")
    outputWithout __slots__:
  2. self.name ← Carol, self.age ← 45

    6class PersonNoSlots:7    def __init__(self⟨PersonNoSlots A⟩, nameCarol, age45):8        self.name→ Carol = nameCarol9        self.age→ 45 = age45
  3. person1 ← ⟨PersonNoSlots A⟩, person1.email ← alice@example.com

    11person1→ ⟨PersonNoSlots A⟩ = PersonNoSlots("Carol", 45)12print(f"Name: {person1.nameCarol}, Age: {person1.age45}")13print(f"Has __dict__: {hasattr(person1⟨PersonNoSlots A⟩, '__dict__')}")14print(f"__dict__: {person1.__dict__{'name': 'Carol', 'age': 45}}")1516# Can add dynamic attributes17person1.email→ alice@example.com = "alice@example.com"18print(f"Added email: {person1.emailalice@example.com}")1920# With __slots__21print("\nWith __slots__:")2223class PersonWithSlots:24    __slots__ = ['name', 'age']25    26    def __init__(self, name, age):27        self.name = name28        self.age = age2930person2 = PersonWithSlots("Bob", 25)31print(f"Name: {person2.name}, Age: {person2.age}")
    outputName: Carol, Age: 45
    Has __dict__: True
    __dict__: {'name': 'Carol', 'age': 45}
    Added email: alice@example.com
    
    With __slots__:
  4. self.name ← Bob, self.age ← 25

    26def __init__(self⟨PersonWithSlots B⟩, nameBob, age25):27    self.name→ Bob = nameBob28    self.age→ 25 = age25
  5. person2 ← ⟨PersonWithSlots B⟩

    30person2→ ⟨PersonWithSlots B⟩ = PersonWithSlots("Bob", 25)31print(f"Name: {person2.nameBob}, Age: {person2.age25}")32print(f"Has __dict__: {hasattr(person2⟨PersonWithSlots B⟩, '__dict__')}")
    outputName: Bob, Age: 25
    Has __dict__: False
  6. except AttributeError as e:

    36    person2.email = "bob@example.com"37except AttributeError as e:38    print(f"Error adding email: {e'PersonWithSlots' object has no attribute 'email'}")
    outputError adding email: 'PersonWithSlots' object has no attribute 'email'
  7. print(" Tuple __slots__:")

    40# Tuple __slots__41print("\nTuple __slots__:")4243class Point:44    __slots__ = ('x', 'y')  # Can use tuple instead of list45    46    def __init__(self, x, y):47        self.x = x48        self.y = y49    50    def __repr__(self):51        return f"Point({self.x}, {self.y})"5253p = Point(10, 20)54print(f"Point: {p}")
    output
    Tuple __slots__:
  8. self.x ← 10, self.y ← 20

    46def __init__(self(empty), x10, y20):47    self.x→ 10 = x1048    self.y→ 20 = y20
  9. p ← Point(10, 20)

    53p→ Point(10, 20) = Point(10, 20)54print(f"Point: {pPoint(10, 20)}")55print(f"x={p.x10}, y={p.y20}")5657# Multiple attributes58print("\nMultiple attributes:")5960class User:61    __slots__ = ['user_id', 'username', 'email', 'created_at']62    63    def __init__(self, user_id, username, email, created_at):64        self.user_id = user_id65        self.username = username66        self.email = email67        self.created_at = created_at68    69    def __repr__(self):70        return f"User(id={self.user_id}, username='{self.username}')"7172user = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {user}")
    outputPoint: Point(10, 20)
    x=10, y=20
    
    Multiple attributes:
  10. self.user_id ← 1, self.username ← alice, self.email ← alice@example.com

    63def __init__(self(empty), user_id1, usernamealice, emailalice@example.com, created_at2024-01-01):64    self.user_id→ 1 = user_id165    self.username→ alice = usernamealice66    self.email→ alice@example.com = emailalice@example.com67    self.created_at→ 2024-01-01 = created_at2024-01-01
  11. user ← User(id=1, username='alice')

    72user→ User(id=1, username='alice') = User(1, "alice", "alice@example.com", "2024-01-01")73print(f"User: {userUser(id=1, username='alice')}")7475# Read-only slots76print("\nRead-only slots:")7778class Config:79    __slots__ = ['_host', '_port']80    81    def __init__(self, host, port):82        self._host = host83        self._port = port84    85    @property86    def host(self):87        return self._host88    89    @property90    def port(self):91        return self._port9293config = Config("localhost", 8080)94print(f"Config: {config.host}:{config.port}")
    outputUser: User(id=1, username='alice')
    
    Read-only slots:
  12. self._host ← localhost, self._port ← 8080

    81def __init__(self⟨Config C⟩, hostlocalhost, port8080):82    self._host→ localhost = hostlocalhost83    self._port→ 8080 = port8080
  13. config ← ⟨Config C⟩

    93config→ ⟨Config C⟩ = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
  14. def host(self):

    85@property86def host(self⟨Config C⟩):87    return self._hostlocalhost
  15. def port(self):

    89@property90def port(self⟨Config C⟩):91    return self._port8080
  16. print(f"Config: {config.host}:{config.port}")

    93config = Config("localhost", 8080)94print(f"Config: {config.hostlocalhost}:{config.port8080}")
    outputConfig: localhost:8080
  17. except AttributeError as e:

    98    config.host = "0.0.0.0"99except AttributeError as e:100    print(f"Error: {eproperty 'host' of 'Config' object has no setter}")
    outputError: property 'host' of 'Config' object has no setter
  18. VALUE ← (empty), im ← ⟨Immutable D⟩

    102# Empty __slots__103print("\nEmpty __slots__:")104105class Immutable:106    __slots__ = []  # No instance attributes allowed107    108    VALUE→ (empty) = 42  # Class attribute is OK109110im→ ⟨Immutable D⟩ = Immutable()111print(f"Class value: {im.VALUE42}")
    output
    Empty __slots__:
    Class value: 42
  19. except AttributeError as e:

    114    im.x = 10115except AttributeError as e:116    print(f"Error: {e'Immutable' object has no attribute 'x'}")
    outputError: 'Immutable' object has no attribute 'x'
  20. print(f"__slots__: {Example.__slots__}")

    118# Checking __slots__119print("\nChecking __slots__:")120121class Example:122    __slots__ = ['a', 'b', 'c']123124print(f"__slots__: {Example.__slots__['a', 'b', 'c']}")125print(f"Allowed attributes: {', '.join(Example.__slots__['a', 'b', 'c'])}")126127# Practical example128print("\nPractical example:")129130class Vector2D:131    __slots__ = ['x', 'y']132    133    def __init__(self, x=0, y=0):134        self.x = x135        self.y = y136    137    def __repr__(self):138        return f"Vector2D({self.x}, {self.y})"139    140    def __add__(self, other):141        return Vector2D(self.x + other.x, self.y + other.y)142    143    def magnitude(self):144        return (self.x ** 2 + self.y ** 2) ** 0.5145146v1 = Vector2D(3, 4)147v2 = Vector2D(1, 2)
    output
    Checking __slots__:
    __slots__: ['a', 'b', 'c']
    Allowed attributes: a, b, c
    
    Practical example:
  21. self.x ← 3, self.y ← 4

    pass 1 of 3
    133def __init__(self(empty), x3=0, y4=0):134    self.x→ 3 = x3135    self.y→ 4 = y4
    All 3 passes — pass 1 is the card above
    passxyself.xself.y
    13434
    21212
    34646
  22. v1 ← Vector2D(3, 4)

    146v1→ Vector2D(3, 4) = Vector2D(3, 4)147v2 = Vector2D(1, 2)148v3 = v1 + v2
  23. v2 ← Vector2D(1, 2)

    146v1 = Vector2D(3, 4)147v2→ Vector2D(1, 2) = Vector2D(1, 2)148v3 = v1Vector2D(3, 4) + v2Vector2D(1, 2)
  24. def __add__(self, other):

    140def __add__(selfVector2D(3, 4), otherVector2D(1, 2)):141    return Vector2D(self.x3 + other.x1, self.y4 + other.y2)
  25. v3 ← Vector2D(4, 6)

    147v2 = Vector2D(1, 2)148v3→ Vector2D(4, 6) = v1Vector2D(3, 4) + v2Vector2D(1, 2)149150print(f"v1 = {v1Vector2D(3, 4)}")151print(f"v2 = {v2Vector2D(1, 2)}")152print(f"v3 = v1 + v2 = {v3Vector2D(4, 6)}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 = Vector2D(3, 4)
    v2 = Vector2D(1, 2)
    v3 = v1 + v2 = Vector2D(4, 6)
  26. def magnitude(self):

    143def magnitude(selfVector2D(3, 4)):144    return (self.x3 ** 2 + self.y4 ** 2) ** 0.5
  27. print(f"v1 magnitude = {v1.magnitude()}")

    152print(f"v3 = v1 + v2 = {v3}")153print(f"v1 magnitude = {v1Vector2D(3, 4).magnitude()}")
    outputv1 magnitude = 5.0

When you define __slots__, Python uses a more compact internal representation for instances instead of a dictionary.

slots declaration Defining `__slots__` as a list or tuple of attribute names to specify the only attributes instances can have.

Memory Savings

slots_memory_savings.py
Replay: real traced execution (multi-file project)
"""Memory savings with __slots__"""

# Memory comparison
print("Memory comparison:")

import sys

class WithoutSlots:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

class WithSlots:
    __slots__ = ['x', 'y', 'z']

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

# Create single instances
obj_no_slots = WithoutSlots(1, 2, 3)
obj_with_slots = WithSlots(1, 2, 3)

# Get sizes
size_no_slots = sys.getsizeof(obj_no_slots) + sys.getsizeof(obj_no_slots.__dict__)
size_with_slots = sys.getsizeof(obj_with_slots)

print(f"Without __slots__: {size_no_slots} bytes")
print(f"With __slots__: {size_with_slots} bytes")
print(f"Savings: {size_no_slots - size_with_slots} bytes ({100 * (1 - size_with_slots/size_no_slots):.1f}%)")

# Many instances
print("\nMany instances:")

# Create many instances
count = 100

no_slots_list = [WithoutSlots(i, i+1, i+2) for i in range(count)]
with_slots_list = [WithSlots(i, i+1, i+2) for i in range(count)]

# Estimate total size
total_no_slots = sum(sys.getsizeof(obj) + sys.getsizeof(obj.__dict__) for obj in no_slots_list[:100]) / 100 * count
total_with_slots = sum(sys.getsizeof(obj) for obj in with_slots_list[:100]) / 100 * count

print(f"{count} instances:")
print(f"Without __slots__: ~{total_no_slots/1024:.1f} KB")
print(f"With __slots__: ~{total_with_slots/1024:.1f} KB")
print(f"Estimated savings: ~{(total_no_slots - total_with_slots)/1024:.1f} KB")

# Simple data class
print("\nSimple data class:")

class Point:
    __slots__ = ['x', 'y']

    def __init__(self, x, y):
        self.x = x
        self.y = y

# Create many points
points = [Point(i, i*2) for i in range(100)]

# Sample memory usage
sample_size = sys.getsizeof(points[0])
print(f"Point with __slots__: {sample_size} bytes each")
print(f"100 points: ~{sample_size * 100 / 1024:.1f} KB")

# Complex object
print("\nComplex object:")

class PersonNoSlots:
    def __init__(self, name, age, email, city):
        self.name = name
        self.age = age
        self.email = email
        self.city = city

class PersonWithSlots:
    __slots__ = ['name', 'age', 'email', 'city']

    def __init__(self, name, age, email, city):
        self.name = name
        self.age = age
        self.email = email
        self.city = city

p1 = PersonNoSlots("Alice", 30, "alice@example.com", "NYC")
p2 = PersonWithSlots("Alice", 30, "alice@example.com", "NYC")

size1 = sys.getsizeof(p1) + sys.getsizeof(p1.__dict__)
size2 = sys.getsizeof(p2)

print(f"PersonNoSlots: {size1} bytes")
print(f"PersonWithSlots: {size2} bytes")
print(f"Savings per instance: {size1 - size2} bytes")

# Large dataset
print("\nLarge dataset:")

class Record:
    __slots__ = ['id', 'timestamp', 'value', 'status']

    def __init__(self, id, timestamp, value, status):
        self.id = id
        self.timestamp = timestamp
        self.value = value
        self.status = status

# Simulate large dataset
dataset_size = 10000
print(f"Creating {dataset_size} records...")

# Estimate memory (based on sample)
sample = Record(1, 1234567890, 42.5, "active")
record_size = sys.getsizeof(sample)

print(f"Size per record: {record_size} bytes")
print(f"Total for {dataset_size} records: ~{record_size * dataset_size / 1024 / 1024:.1f} MB")

# Time series data
print("\nTime series data:")

class DataPoint:
    __slots__ = ['timestamp', 'value']

    def __init__(self, timestamp, value):
        self.timestamp = timestamp
        self.value = value

# Simulate 1 year of per-minute data
minutes_per_year = 365 * 24 * 60
point_size = sys.getsizeof(DataPoint(0, 0.0))

print(f"Data point size: {point_size} bytes")
print(f"1 year (minute resolution): ~{point_size * minutes_per_year / 1024 / 1024:.1f} MB")

# Practical comparison
print("\nPractical comparison:")

# Coordinates for game
class CoordNoSlots:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

class CoordWithSlots:
    __slots__ = ['x', 'y', 'z']

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

# Simulate game world with many entities
entity_count = 1000

# Sample sizes
no_slots = CoordNoSlots(0, 0, 0)
with_slots = CoordWithSlots(0, 0, 0)

size_no = sys.getsizeof(no_slots) + sys.getsizeof(no_slots.__dict__)
size_with = sys.getsizeof(with_slots)

print(f"{entity_count} game entities:")
print(f"Without __slots__: ~{size_no * entity_count / 1024:.1f} KB")
print(f"With __slots__: ~{size_with * entity_count / 1024:.1f} KB")
print(f"Memory saved: ~{(size_no - size_with) * entity_count / 1024:.1f} KB")

  1. """Memory savings with __slots__"""

    1"""Memory savings with __slots__"""23# Memory comparison4print("Memory comparison:")56import sys78class WithoutSlots:9    def __init__(self, x, y, z):10        self.x = x11        self.y = y12        self.z = z1314class WithSlots:15    __slots__ = ['x', 'y', 'z']16    17    def __init__(self, x, y, z):18        self.x = x19        self.y = y20        self.z = z2122# Create single instances23obj_no_slots = WithoutSlots(1, 2, 3)24obj_with_slots = WithSlots(1, 2, 3)
    outputMemory comparison:
  2. self.x ← 1, self.y ← 2, self.z ← 3

    pass 1 of 101
    8class WithoutSlots:9    def __init__(self⟨WithoutSlots A⟩, x1, y2, z3):10        self.x→ 1 = x111        self.y→ 2 = y212        self.z→ 3 = z3
    101 passes — pass 1 is the card above
    passselfxyzself.xself.yself.z
    1⟨WithoutSlots A⟩123123
    2⟨WithoutSlots B⟩012012
    3⟨WithoutSlots C⟩123123
    4⟨WithoutSlots D⟩234234
    5⟨WithoutSlots E⟩345345
    6⟨WithoutSlots F⟩456456
    7⟨WithoutSlots G⟩567567
    8⟨WithoutSlots H⟩678678
    9⟨WithoutSlots I⟩789789
    ⋯ 90 more passes ⋯
    100⟨WithoutSlots J⟩98991009899100
    101⟨WithoutSlots K⟩9910010199100101
  3. obj_no_slots ← ⟨WithoutSlots A⟩

    22# Create single instances23obj_no_slots→ ⟨WithoutSlots A⟩ = WithoutSlots(1, 2, 3)24obj_with_slots = WithSlots(1, 2, 3)
  4. self.x ← 1, self.y ← 2, self.z ← 3

    pass 1 of 101
    17def __init__(self⟨WithSlots L⟩, x1, y2, z3):18    self.x→ 1 = x119    self.y→ 2 = y220    self.z→ 3 = z3
    101 passes — pass 1 is the card above
    passselfxyzself.xself.yself.z
    1⟨WithSlots L⟩123123
    2⟨WithSlots M⟩012012
    3⟨WithSlots N⟩123123
    4⟨WithSlots O⟩234234
    5⟨WithSlots P⟩345345
    6⟨WithSlots Q⟩456456
    7⟨WithSlots R⟩567567
    8⟨WithSlots S⟩678678
    9⟨WithSlots T⟩789789
    ⋯ 90 more passes ⋯
    100⟨WithSlots U⟩98991009899100
    101⟨WithSlots V⟩9910010199100101
  5. obj_with_slots ← ⟨WithSlots L⟩, size_no_slots ← 344, size_with_slots ← 56

    23obj_no_slots = WithoutSlots(1, 2, 3)24obj_with_slots→ ⟨WithSlots L⟩ = WithSlots(1, 2, 3)2526# Get sizes27size_no_slots→ 344 = sys<module 'sys' (built-in)>.getsizeof(obj_no_slots⟨WithoutSlots A⟩) + sys.getsizeof(obj_no_slots.__dict__{'x': 1, 'y': 2, 'z': 3})28size_with_slots→ 56 = sys<module 'sys' (built-in)>.getsizeof(obj_with_slots⟨WithSlots L⟩)2930print(f"Without __slots__: {size_no_slots344} bytes")31print(f"With __slots__: {size_with_slots56} bytes")32print(f"Savings: {size_no_slots344 - size_with_slots56} bytes ({100 * (1 - size_with_slots/size_no_slots):.1f}%)")3334# Many instances35print("\nMany instances:")3637# Create many instances38count→ 100 = 1003940no_slots_list = [WithoutSlots(i, i+1, i+2) for i in range(count100)]41with_slots_list = [WithSlots(i, i+1, i+2) for i in range(count)]
    outputWithout __slots__: 344 bytes
    With __slots__: 56 bytes
    Savings: 288 bytes (83.7%)
    
    Many instances:
  6. no_slots_list ← [⟨WithoutSlots B⟩, ⟨WithoutSlots C⟩, ⟨WithoutSlots D⟩, ⟨WithoutSlots E⟩, ⟨WithoutSlots F⟩, ⟨WithoutSlots G⟩, ⟨WithoutSlots H⟩, ⟨WithoutSlots I⟩, ⟨WithoutSlots W⟩, ⟨WithoutSlots X⟩, ⟨WithoutSlots Y⟩, ⟨WithoutSlots Z⟩, ⟨WithoutSlots AA⟩, ⟨WithoutSlots AB⟩, ⟨WithoutSlots AC⟩, ⟨WithoutSlots AD⟩, ⟨WithoutSlots AE⟩, ⟨WithoutSlots AF⟩, ⟨WithoutSlots AG⟩, ⟨WithoutSlots AH⟩, ⟨WithoutSlots AI⟩, ⟨WithoutSlots AJ⟩, ⟨WithoutSlots AK⟩, ⟨WithoutSlots AL⟩, ⟨WithoutSlots AM⟩, ⟨WithoutSlots AN⟩, ⟨WithoutSlots AO⟩, ⟨WithoutSlots AP⟩, ⟨WithoutSlots AQ⟩, ⟨WithoutSlots AR⟩, ⟨WithoutSlots AS⟩, ⟨WithoutSlots AT⟩, ⟨WithoutSlots AU⟩, ⟨WithoutSlots AV⟩, ⟨WithoutSlots AW⟩, ⟨WithoutSlots AX⟩, ⟨WithoutSlots AY⟩, ⟨WithoutSlots AZ⟩, ⟨WithoutSlots BA⟩, ⟨WithoutSlots BB⟩, ⟨WithoutSlots BC⟩, ⟨WithoutSlots BD⟩, ⟨WithoutSlots BE⟩, ⟨WithoutSlots BF⟩, ⟨WithoutSlots BG⟩, ⟨WithoutSlots BH⟩, ⟨WithoutSlots BI⟩, ⟨WithoutSlots BJ⟩, ⟨WithoutSlots BK⟩, ⟨WithoutSlots BL⟩, ⟨WithoutSlots BM⟩, ⟨WithoutSlots BN⟩, ⟨WithoutSlots BO⟩, ⟨WithoutSlots BP⟩, ⟨WithoutSlots BQ⟩, ⟨WithoutSlots BR⟩, ⟨WithoutSlots BS⟩, ⟨WithoutSlots BT⟩, ⟨WithoutSlots BU⟩, ⟨WithoutSlots BV⟩, ⟨WithoutSlots BW⟩, ⟨WithoutSlots BX⟩, ⟨WithoutSlots BY⟩, ⟨WithoutSlots BZ⟩, ⟨WithoutSlots CA⟩, ⟨WithoutSlots CB⟩, ⟨WithoutSlots CC⟩, ⟨WithoutSlots CD⟩, ⟨WithoutSlots CE⟩, ⟨WithoutSlots CF⟩, ⟨WithoutSlots CG⟩, ⟨WithoutSlots CH⟩, ⟨WithoutSlots CI⟩, ⟨WithoutSlots CJ⟩, ⟨WithoutSlots CK⟩, ⟨WithoutSlots CL⟩, ⟨WithoutSlots CM⟩, ⟨WithoutSlots CN⟩, ⟨WithoutSlots CO⟩, ⟨WithoutSlots CP⟩, ⟨WithoutSlots CQ⟩, ⟨WithoutSlots CR⟩, ⟨WithoutSlots CS⟩, ⟨WithoutSlots CT⟩, ⟨WithoutSlots CU⟩, ⟨WithoutSlots CV⟩, ⟨WithoutSlots CW⟩, ⟨WithoutSlots CX⟩, ⟨WithoutSlots CY⟩, ⟨WithoutSlots CZ⟩, ⟨WithoutSlots DA⟩, ⟨WithoutSlots DB⟩, ⟨WithoutSlots DC⟩, ⟨WithoutSlots DD⟩, ⟨WithoutSlots DE⟩, ⟨WithoutSlots DF⟩, ⟨WithoutSlots DG⟩, ⟨WithoutSlots DH⟩, ⟨WithoutSlots J⟩, ⟨WithoutSlots K⟩]

    40no_slots_list→ [⟨WithoutSlots B⟩, ⟨WithoutSlots C⟩, ⟨WithoutSlots D⟩, ⟨WithoutSlots E⟩, ⟨WithoutSlots F⟩, ⟨WithoutSlots G⟩, ⟨WithoutSlots H⟩, ⟨WithoutSlots I⟩, ⟨WithoutSlots W⟩, ⟨WithoutSlots X⟩, ⟨WithoutSlots Y⟩, ⟨WithoutSlots Z⟩, ⟨WithoutSlots AA⟩, ⟨WithoutSlots AB⟩, ⟨WithoutSlots AC⟩, ⟨WithoutSlots AD⟩, ⟨WithoutSlots AE⟩, ⟨WithoutSlots AF⟩, ⟨WithoutSlots AG⟩, ⟨WithoutSlots AH⟩, ⟨WithoutSlots AI⟩, ⟨WithoutSlots AJ⟩, ⟨WithoutSlots AK⟩, ⟨WithoutSlots AL⟩, ⟨WithoutSlots AM⟩, ⟨WithoutSlots AN⟩, ⟨WithoutSlots AO⟩, ⟨WithoutSlots AP⟩, ⟨WithoutSlots AQ⟩, ⟨WithoutSlots AR⟩, ⟨WithoutSlots AS⟩, ⟨WithoutSlots AT⟩, ⟨WithoutSlots AU⟩, ⟨WithoutSlots AV⟩, ⟨WithoutSlots AW⟩, ⟨WithoutSlots AX⟩, ⟨WithoutSlots AY⟩, ⟨WithoutSlots AZ⟩, ⟨WithoutSlots BA⟩, ⟨WithoutSlots BB⟩, ⟨WithoutSlots BC⟩, ⟨WithoutSlots BD⟩, ⟨WithoutSlots BE⟩, ⟨WithoutSlots BF⟩, ⟨WithoutSlots BG⟩, ⟨WithoutSlots BH⟩, ⟨WithoutSlots BI⟩, ⟨WithoutSlots BJ⟩, ⟨WithoutSlots BK⟩, ⟨WithoutSlots BL⟩, ⟨WithoutSlots BM⟩, ⟨WithoutSlots BN⟩, ⟨WithoutSlots BO⟩, ⟨WithoutSlots BP⟩, ⟨WithoutSlots BQ⟩, ⟨WithoutSlots BR⟩, ⟨WithoutSlots BS⟩, ⟨WithoutSlots BT⟩, ⟨WithoutSlots BU⟩, ⟨WithoutSlots BV⟩, ⟨WithoutSlots BW⟩, ⟨WithoutSlots BX⟩, ⟨WithoutSlots BY⟩, ⟨WithoutSlots BZ⟩, ⟨WithoutSlots CA⟩, ⟨WithoutSlots CB⟩, ⟨WithoutSlots CC⟩, ⟨WithoutSlots CD⟩, ⟨WithoutSlots CE⟩, ⟨WithoutSlots CF⟩, ⟨WithoutSlots CG⟩, ⟨WithoutSlots CH⟩, ⟨WithoutSlots CI⟩, ⟨WithoutSlots CJ⟩, ⟨WithoutSlots CK⟩, ⟨WithoutSlots CL⟩, ⟨WithoutSlots CM⟩, ⟨WithoutSlots CN⟩, ⟨WithoutSlots CO⟩, ⟨WithoutSlots CP⟩, ⟨WithoutSlots CQ⟩, ⟨WithoutSlots CR⟩, ⟨WithoutSlots CS⟩, ⟨WithoutSlots CT⟩, ⟨WithoutSlots CU⟩, ⟨WithoutSlots CV⟩, ⟨WithoutSlots CW⟩, ⟨WithoutSlots CX⟩, ⟨WithoutSlots CY⟩, ⟨WithoutSlots CZ⟩, ⟨WithoutSlots DA⟩, ⟨WithoutSlots DB⟩, ⟨WithoutSlots DC⟩, ⟨WithoutSlots DD⟩, ⟨WithoutSlots DE⟩, ⟨WithoutSlots DF⟩, ⟨WithoutSlots DG⟩, ⟨WithoutSlots DH⟩, ⟨WithoutSlots J⟩, ⟨WithoutSlots K⟩] = [WithoutSlots(i, i+1, i+2) for i in range(count100)]41with_slots_list = [WithSlots(i, i+1, i+2) for i in range(count100)]
  7. with_slots_list ← [⟨WithSlots M⟩, ⟨WithSlots N⟩, ⟨WithSlots O⟩, ⟨WithSlots P⟩, ⟨WithSlots Q⟩, ⟨WithSlots R⟩, ⟨WithSlots S⟩, ⟨WithSlots T⟩, ⟨WithSlots DI⟩, ⟨WithSlots DJ⟩, ⟨WithSlots DK⟩, ⟨WithSlots DL⟩, ⟨WithSlots DM⟩, ⟨WithSlots DN⟩, ⟨WithSlots DO⟩, ⟨WithSlots DP⟩, ⟨WithSlots DQ⟩, ⟨WithSlots DR⟩, ⟨WithSlots DS⟩, ⟨WithSlots DT⟩, ⟨WithSlots DU⟩, ⟨WithSlots DV⟩, ⟨WithSlots DW⟩, ⟨WithSlots DX⟩, ⟨WithSlots DY⟩, ⟨WithSlots DZ⟩, ⟨WithSlots EA⟩, ⟨WithSlots EB⟩, ⟨WithSlots EC⟩, ⟨WithSlots ED⟩, ⟨WithSlots EE⟩, ⟨WithSlots EF⟩, ⟨WithSlots EG⟩, ⟨WithSlots EH⟩, ⟨WithSlots EI⟩, ⟨WithSlots EJ⟩, ⟨WithSlots EK⟩, ⟨WithSlots EL⟩, ⟨WithSlots EM⟩, ⟨WithSlots EN⟩, ⟨WithSlots EO⟩, ⟨WithSlots EP⟩, ⟨WithSlots EQ⟩, ⟨WithSlots ER⟩, ⟨WithSlots ES⟩, ⟨WithSlots ET⟩, ⟨WithSlots EU⟩, ⟨WithSlots EV⟩, ⟨WithSlots EW⟩, ⟨WithSlots EX⟩, ⟨WithSlots EY⟩, ⟨WithSlots EZ⟩, ⟨WithSlots FA⟩, ⟨WithSlots FB⟩, ⟨WithSlots FC⟩, ⟨WithSlots FD⟩, ⟨WithSlots FE⟩, ⟨WithSlots FF⟩, ⟨WithSlots FG⟩, ⟨WithSlots FH⟩, ⟨WithSlots FI⟩, ⟨WithSlots FJ⟩, ⟨WithSlots FK⟩, ⟨WithSlots FL⟩, ⟨WithSlots FM⟩, ⟨WithSlots FN⟩, ⟨WithSlots FO⟩, ⟨WithSlots FP⟩, ⟨WithSlots FQ⟩, ⟨WithSlots FR⟩, ⟨WithSlots FS⟩, ⟨WithSlots FT⟩, ⟨WithSlots FU⟩, ⟨WithSlots FV⟩, ⟨WithSlots FW⟩, ⟨WithSlots FX⟩, ⟨WithSlots FY⟩, ⟨WithSlots FZ⟩, ⟨WithSlots GA⟩, ⟨WithSlots GB⟩, ⟨WithSlots GC⟩, ⟨WithSlots GD⟩, ⟨WithSlots GE⟩, ⟨WithSlots GF⟩, ⟨WithSlots GG⟩, ⟨WithSlots GH⟩, ⟨WithSlots GI⟩, ⟨WithSlots GJ⟩, ⟨WithSlots GK⟩, ⟨WithSlots GL⟩, ⟨WithSlots GM⟩, ⟨WithSlots GN⟩, ⟨WithSlots GO⟩, ⟨WithSlots GP⟩, ⟨WithSlots GQ⟩, ⟨WithSlots GR⟩, ⟨WithSlots GS⟩, ⟨WithSlots GT⟩, ⟨WithSlots U⟩, ⟨WithSlots V⟩]

    40no_slots_list = [WithoutSlots(i, i+1, i+2) for i in range(count)]41with_slots_list→ [⟨WithSlots M⟩, ⟨WithSlots N⟩, ⟨WithSlots O⟩, ⟨WithSlots P⟩, ⟨WithSlots Q⟩, ⟨WithSlots R⟩, ⟨WithSlots S⟩, ⟨WithSlots T⟩, ⟨WithSlots DI⟩, ⟨WithSlots DJ⟩, ⟨WithSlots DK⟩, ⟨WithSlots DL⟩, ⟨WithSlots DM⟩, ⟨WithSlots DN⟩, ⟨WithSlots DO⟩, ⟨WithSlots DP⟩, ⟨WithSlots DQ⟩, ⟨WithSlots DR⟩, ⟨WithSlots DS⟩, ⟨WithSlots DT⟩, ⟨WithSlots DU⟩, ⟨WithSlots DV⟩, ⟨WithSlots DW⟩, ⟨WithSlots DX⟩, ⟨WithSlots DY⟩, ⟨WithSlots DZ⟩, ⟨WithSlots EA⟩, ⟨WithSlots EB⟩, ⟨WithSlots EC⟩, ⟨WithSlots ED⟩, ⟨WithSlots EE⟩, ⟨WithSlots EF⟩, ⟨WithSlots EG⟩, ⟨WithSlots EH⟩, ⟨WithSlots EI⟩, ⟨WithSlots EJ⟩, ⟨WithSlots EK⟩, ⟨WithSlots EL⟩, ⟨WithSlots EM⟩, ⟨WithSlots EN⟩, ⟨WithSlots EO⟩, ⟨WithSlots EP⟩, ⟨WithSlots EQ⟩, ⟨WithSlots ER⟩, ⟨WithSlots ES⟩, ⟨WithSlots ET⟩, ⟨WithSlots EU⟩, ⟨WithSlots EV⟩, ⟨WithSlots EW⟩, ⟨WithSlots EX⟩, ⟨WithSlots EY⟩, ⟨WithSlots EZ⟩, ⟨WithSlots FA⟩, ⟨WithSlots FB⟩, ⟨WithSlots FC⟩, ⟨WithSlots FD⟩, ⟨WithSlots FE⟩, ⟨WithSlots FF⟩, ⟨WithSlots FG⟩, ⟨WithSlots FH⟩, ⟨WithSlots FI⟩, ⟨WithSlots FJ⟩, ⟨WithSlots FK⟩, ⟨WithSlots FL⟩, ⟨WithSlots FM⟩, ⟨WithSlots FN⟩, ⟨WithSlots FO⟩, ⟨WithSlots FP⟩, ⟨WithSlots FQ⟩, ⟨WithSlots FR⟩, ⟨WithSlots FS⟩, ⟨WithSlots FT⟩, ⟨WithSlots FU⟩, ⟨WithSlots FV⟩, ⟨WithSlots FW⟩, ⟨WithSlots FX⟩, ⟨WithSlots FY⟩, ⟨WithSlots FZ⟩, ⟨WithSlots GA⟩, ⟨WithSlots GB⟩, ⟨WithSlots GC⟩, ⟨WithSlots GD⟩, ⟨WithSlots GE⟩, ⟨WithSlots GF⟩, ⟨WithSlots GG⟩, ⟨WithSlots GH⟩, ⟨WithSlots GI⟩, ⟨WithSlots GJ⟩, ⟨WithSlots GK⟩, ⟨WithSlots GL⟩, ⟨WithSlots GM⟩, ⟨WithSlots GN⟩, ⟨WithSlots GO⟩, ⟨WithSlots GP⟩, ⟨WithSlots GQ⟩, ⟨WithSlots GR⟩, ⟨WithSlots GS⟩, ⟨WithSlots GT⟩, ⟨WithSlots U⟩, ⟨WithSlots V⟩] = [WithSlots(i, i+1, i+2) for i in range(count100)]4243# Estimate total size44total_no_slots→ 14400.0 = sum(sys<module 'sys' (built-in)>.getsizeof(obj) + sys.getsizeof(obj.__dict__(empty)) for obj in no_slots_list[:100][⟨WithoutSlots B⟩, ⟨WithoutSlots C⟩, ⟨WithoutSlots D⟩, ⟨WithoutSlots E⟩, ⟨WithoutSlots F⟩, ⟨WithoutSlots G⟩, ⟨WithoutSlots H⟩, ⟨WithoutSlots I⟩, ⟨WithoutSlots W⟩, ⟨WithoutSlots X⟩, ⟨WithoutSlots Y⟩, ⟨WithoutSlots Z⟩, ⟨WithoutSlots AA⟩, ⟨WithoutSlots AB⟩, ⟨WithoutSlots AC⟩, ⟨WithoutSlots AD⟩, ⟨WithoutSlots AE⟩, ⟨WithoutSlots AF⟩, ⟨WithoutSlots AG⟩, ⟨WithoutSlots AH⟩, ⟨WithoutSlots AI⟩, ⟨WithoutSlots AJ⟩, ⟨WithoutSlots AK⟩, ⟨WithoutSlots AL⟩, ⟨WithoutSlots AM⟩, ⟨WithoutSlots AN⟩, ⟨WithoutSlots AO⟩, ⟨WithoutSlots AP⟩, ⟨WithoutSlots AQ⟩, ⟨WithoutSlots AR⟩, ⟨WithoutSlots AS⟩, ⟨WithoutSlots AT⟩, ⟨WithoutSlots AU⟩, ⟨WithoutSlots AV⟩, ⟨WithoutSlots AW⟩, ⟨WithoutSlots AX⟩, ⟨WithoutSlots AY⟩, ⟨WithoutSlots AZ⟩, ⟨WithoutSlots BA⟩, ⟨WithoutSlots BB⟩, ⟨WithoutSlots BC⟩, ⟨WithoutSlots BD⟩, ⟨WithoutSlots BE⟩, ⟨WithoutSlots BF⟩, ⟨WithoutSlots BG⟩, ⟨WithoutSlots BH⟩, ⟨WithoutSlots BI⟩, ⟨WithoutSlots BJ⟩, ⟨WithoutSlots BK⟩, ⟨WithoutSlots BL⟩, ⟨WithoutSlots BM⟩, ⟨WithoutSlots BN⟩, ⟨WithoutSlots BO⟩, ⟨WithoutSlots BP⟩, ⟨WithoutSlots BQ⟩, ⟨WithoutSlots BR⟩, ⟨WithoutSlots BS⟩, ⟨WithoutSlots BT⟩, ⟨WithoutSlots BU⟩, ⟨WithoutSlots BV⟩, ⟨WithoutSlots BW⟩, ⟨WithoutSlots BX⟩, ⟨WithoutSlots BY⟩, ⟨WithoutSlots BZ⟩, ⟨WithoutSlots CA⟩, ⟨WithoutSlots CB⟩, ⟨WithoutSlots CC⟩, ⟨WithoutSlots CD⟩, ⟨WithoutSlots CE⟩, ⟨WithoutSlots CF⟩, ⟨WithoutSlots CG⟩, ⟨WithoutSlots CH⟩, ⟨WithoutSlots CI⟩, ⟨WithoutSlots CJ⟩, ⟨WithoutSlots CK⟩, ⟨WithoutSlots CL⟩, ⟨WithoutSlots CM⟩, ⟨WithoutSlots CN⟩, ⟨WithoutSlots CO⟩, ⟨WithoutSlots CP⟩, ⟨WithoutSlots CQ⟩, ⟨WithoutSlots CR⟩, ⟨WithoutSlots CS⟩, ⟨WithoutSlots CT⟩, ⟨WithoutSlots CU⟩, ⟨WithoutSlots CV⟩, ⟨WithoutSlots CW⟩, ⟨WithoutSlots CX⟩, ⟨WithoutSlots CY⟩, ⟨WithoutSlots CZ⟩, ⟨WithoutSlots DA⟩, ⟨WithoutSlots DB⟩, ⟨WithoutSlots DC⟩, ⟨WithoutSlots DD⟩, ⟨WithoutSlots DE⟩, ⟨WithoutSlots DF⟩, ⟨WithoutSlots DG⟩, ⟨WithoutSlots DH⟩, ⟨WithoutSlots J⟩, ⟨WithoutSlots K⟩]) / 100 * count10045total_with_slots→ 5600.0 = sum(sys<module 'sys' (built-in)>.getsizeof(obj) for obj in with_slots_list[:100][⟨WithSlots M⟩, ⟨WithSlots N⟩, ⟨WithSlots O⟩, ⟨WithSlots P⟩, ⟨WithSlots Q⟩, ⟨WithSlots R⟩, ⟨WithSlots S⟩, ⟨WithSlots T⟩, ⟨WithSlots DI⟩, ⟨WithSlots DJ⟩, ⟨WithSlots DK⟩, ⟨WithSlots DL⟩, ⟨WithSlots DM⟩, ⟨WithSlots DN⟩, ⟨WithSlots DO⟩, ⟨WithSlots DP⟩, ⟨WithSlots DQ⟩, ⟨WithSlots DR⟩, ⟨WithSlots DS⟩, ⟨WithSlots DT⟩, ⟨WithSlots DU⟩, ⟨WithSlots DV⟩, ⟨WithSlots DW⟩, ⟨WithSlots DX⟩, ⟨WithSlots DY⟩, ⟨WithSlots DZ⟩, ⟨WithSlots EA⟩, ⟨WithSlots EB⟩, ⟨WithSlots EC⟩, ⟨WithSlots ED⟩, ⟨WithSlots EE⟩, ⟨WithSlots EF⟩, ⟨WithSlots EG⟩, ⟨WithSlots EH⟩, ⟨WithSlots EI⟩, ⟨WithSlots EJ⟩, ⟨WithSlots EK⟩, ⟨WithSlots EL⟩, ⟨WithSlots EM⟩, ⟨WithSlots EN⟩, ⟨WithSlots EO⟩, ⟨WithSlots EP⟩, ⟨WithSlots EQ⟩, ⟨WithSlots ER⟩, ⟨WithSlots ES⟩, ⟨WithSlots ET⟩, ⟨WithSlots EU⟩, ⟨WithSlots EV⟩, ⟨WithSlots EW⟩, ⟨WithSlots EX⟩, ⟨WithSlots EY⟩, ⟨WithSlots EZ⟩, ⟨WithSlots FA⟩, ⟨WithSlots FB⟩, ⟨WithSlots FC⟩, ⟨WithSlots FD⟩, ⟨WithSlots FE⟩, ⟨WithSlots FF⟩, ⟨WithSlots FG⟩, ⟨WithSlots FH⟩, ⟨WithSlots FI⟩, ⟨WithSlots FJ⟩, ⟨WithSlots FK⟩, ⟨WithSlots FL⟩, ⟨WithSlots FM⟩, ⟨WithSlots FN⟩, ⟨WithSlots FO⟩, ⟨WithSlots FP⟩, ⟨WithSlots FQ⟩, ⟨WithSlots FR⟩, ⟨WithSlots FS⟩, ⟨WithSlots FT⟩, ⟨WithSlots FU⟩, ⟨WithSlots FV⟩, ⟨WithSlots FW⟩, ⟨WithSlots FX⟩, ⟨WithSlots FY⟩, ⟨WithSlots FZ⟩, ⟨WithSlots GA⟩, ⟨WithSlots GB⟩, ⟨WithSlots GC⟩, ⟨WithSlots GD⟩, ⟨WithSlots GE⟩, ⟨WithSlots GF⟩, ⟨WithSlots GG⟩, ⟨WithSlots GH⟩, ⟨WithSlots GI⟩, ⟨WithSlots GJ⟩, ⟨WithSlots GK⟩, ⟨WithSlots GL⟩, ⟨WithSlots GM⟩, ⟨WithSlots GN⟩, ⟨WithSlots GO⟩, ⟨WithSlots GP⟩, ⟨WithSlots GQ⟩, ⟨WithSlots GR⟩, ⟨WithSlots GS⟩, ⟨WithSlots GT⟩, ⟨WithSlots U⟩, ⟨WithSlots V⟩]) / 100 * count1004647print(f"{count100} instances:")48print(f"Without __slots__: ~{total_no_slots14400.0/1024:.1f} KB")49print(f"With __slots__: ~{total_with_slots5600.0/1024:.1f} KB")50print(f"Estimated savings: ~{(total_no_slots14400.0 - total_with_slots5600.0)/1024:.1f} KB")5152# Simple data class53print("\nSimple data class:")5455class Point:56    __slots__ = ['x', 'y']57    58    def __init__(self, x, y):59        self.x = x60        self.y = y6162# Create many points63points = [Point(i, i*2) for i in range(100)]
    output100 instances:
    Without __slots__: ~14.1 KB
    With __slots__: ~5.5 KB
    Estimated savings: ~8.6 KB
    
    Simple data class:
  8. self.x ← 0, self.y ← 0

    pass 1 of 100
    58def __init__(self⟨Point GU⟩, x0, y0):59    self.x→ 0 = x060    self.y→ 0 = y0
    100 passes — pass 1 is the card above
    passselfxyself.xself.y
    1⟨Point GU⟩0000
    2⟨Point GV⟩1212
    3⟨Point GW⟩2424
    4⟨Point GX⟩3636
    5⟨Point GY⟩4848
    6⟨Point GZ⟩510510
    7⟨Point HA⟩612612
    8⟨Point HB⟩714714
    9⟨Point HC⟩816816
    ⋯ 89 more passes ⋯
    99⟨Point HD⟩9819698196
    100⟨Point HE⟩9919899198
  9. points ← [⟨Point GU⟩, ⟨Point GV⟩, ⟨Point GW⟩, ⟨Point GX⟩, ⟨Point GY⟩, ⟨Point GZ⟩, ⟨Point HA⟩, ⟨Point HB⟩, ⟨Point HC⟩, ⟨Point HF⟩, ⟨Point HG⟩, ⟨Point HH⟩, ⟨Point HI⟩, ⟨Point HJ⟩, ⟨Point HK⟩, ⟨Point HL⟩, ⟨Point HM⟩, ⟨Point HN⟩, ⟨Point HO⟩, ⟨Point HP⟩, ⟨Point HQ⟩, ⟨Point HR⟩, ⟨Point HS⟩, ⟨Point HT⟩, ⟨Point HU⟩, ⟨Point HV⟩, ⟨Point HW⟩, ⟨Point HX⟩, ⟨Point HY⟩, ⟨Point HZ⟩, ⟨Point IA⟩, ⟨Point IB⟩, ⟨Point IC⟩, ⟨Point ID⟩, ⟨Point IE⟩, ⟨Point IF⟩, ⟨Point IG⟩, ⟨Point IH⟩, ⟨Point II⟩, ⟨Point IJ⟩, ⟨Point IK⟩, ⟨Point IL⟩, ⟨Point IM⟩, ⟨Point IN⟩, ⟨Point IO⟩, ⟨Point IP⟩, ⟨Point IQ⟩, ⟨Point IR⟩, ⟨Point IS⟩, ⟨Point IT⟩, ⟨Point IU⟩, ⟨Point IV⟩, ⟨Point IW⟩, ⟨Point IX⟩, ⟨Point IY⟩, ⟨Point IZ⟩, ⟨Point JA⟩, ⟨Point JB⟩, ⟨Point JC⟩, ⟨Point JD⟩, ⟨Point JE⟩, ⟨Point JF⟩, ⟨Point JG⟩, ⟨Point JH⟩, ⟨Point JI⟩, ⟨Point JJ⟩, ⟨Point JK⟩, ⟨Point JL⟩, ⟨Point JM⟩, ⟨Point JN⟩, ⟨Point JO⟩, ⟨Point JP⟩, ⟨Point JQ⟩, ⟨Point JR⟩, ⟨Point JS⟩, ⟨Point JT⟩, ⟨Point JU⟩, ⟨Point JV⟩, ⟨Point JW⟩, ⟨Point JX⟩, ⟨Point JY⟩, ⟨Point JZ⟩, ⟨Point KA⟩, ⟨Point KB⟩, ⟨Point KC⟩, ⟨Point KD⟩, ⟨Point KE⟩, ⟨Point KF⟩, ⟨Point KG⟩, ⟨Point KH⟩, ⟨Point KI⟩, ⟨Point KJ⟩, ⟨Point KK⟩, ⟨Point KL⟩, ⟨Point KM⟩, ⟨Point KN⟩, ⟨Point KO⟩, ⟨Point KP⟩, ⟨Point HD⟩, ⟨Point HE⟩]

    62# Create many points63points→ [⟨Point GU⟩, ⟨Point GV⟩, ⟨Point GW⟩, ⟨Point GX⟩, ⟨Point GY⟩, ⟨Point GZ⟩, ⟨Point HA⟩, ⟨Point HB⟩, ⟨Point HC⟩, ⟨Point HF⟩, ⟨Point HG⟩, ⟨Point HH⟩, ⟨Point HI⟩, ⟨Point HJ⟩, ⟨Point HK⟩, ⟨Point HL⟩, ⟨Point HM⟩, ⟨Point HN⟩, ⟨Point HO⟩, ⟨Point HP⟩, ⟨Point HQ⟩, ⟨Point HR⟩, ⟨Point HS⟩, ⟨Point HT⟩, ⟨Point HU⟩, ⟨Point HV⟩, ⟨Point HW⟩, ⟨Point HX⟩, ⟨Point HY⟩, ⟨Point HZ⟩, ⟨Point IA⟩, ⟨Point IB⟩, ⟨Point IC⟩, ⟨Point ID⟩, ⟨Point IE⟩, ⟨Point IF⟩, ⟨Point IG⟩, ⟨Point IH⟩, ⟨Point II⟩, ⟨Point IJ⟩, ⟨Point IK⟩, ⟨Point IL⟩, ⟨Point IM⟩, ⟨Point IN⟩, ⟨Point IO⟩, ⟨Point IP⟩, ⟨Point IQ⟩, ⟨Point IR⟩, ⟨Point IS⟩, ⟨Point IT⟩, ⟨Point IU⟩, ⟨Point IV⟩, ⟨Point IW⟩, ⟨Point IX⟩, ⟨Point IY⟩, ⟨Point IZ⟩, ⟨Point JA⟩, ⟨Point JB⟩, ⟨Point JC⟩, ⟨Point JD⟩, ⟨Point JE⟩, ⟨Point JF⟩, ⟨Point JG⟩, ⟨Point JH⟩, ⟨Point JI⟩, ⟨Point JJ⟩, ⟨Point JK⟩, ⟨Point JL⟩, ⟨Point JM⟩, ⟨Point JN⟩, ⟨Point JO⟩, ⟨Point JP⟩, ⟨Point JQ⟩, ⟨Point JR⟩, ⟨Point JS⟩, ⟨Point JT⟩, ⟨Point JU⟩, ⟨Point JV⟩, ⟨Point JW⟩, ⟨Point JX⟩, ⟨Point JY⟩, ⟨Point JZ⟩, ⟨Point KA⟩, ⟨Point KB⟩, ⟨Point KC⟩, ⟨Point KD⟩, ⟨Point KE⟩, ⟨Point KF⟩, ⟨Point KG⟩, ⟨Point KH⟩, ⟨Point KI⟩, ⟨Point KJ⟩, ⟨Point KK⟩, ⟨Point KL⟩, ⟨Point KM⟩, ⟨Point KN⟩, ⟨Point KO⟩, ⟨Point KP⟩, ⟨Point HD⟩, ⟨Point HE⟩] = [Point(i, i*2) for i in range(100)]6465# Sample memory usage66sample_size→ 48 = sys<module 'sys' (built-in)>.getsizeof(points[0]⟨Point GU⟩)67print(f"Point with __slots__: {sample_size48} bytes each")68print(f"100 points: ~{sample_size48 * 100 / 1024:.1f} KB")6970# Complex object71print("\nComplex object:")7273class PersonNoSlots:74    def __init__(self, name, age, email, city):75        self.name = name76        self.age = age77        self.email = email78        self.city = city7980class PersonWithSlots:81    __slots__ = ['name', 'age', 'email', 'city']82    83    def __init__(self, name, age, email, city):84        self.name = name85        self.age = age86        self.email = email87        self.city = city8889p1 = PersonNoSlots("Alice", 30, "alice@example.com", "NYC")90p2 = PersonWithSlots("Alice", 30, "alice@example.com", "NYC")
    outputPoint with __slots__: 48 bytes each
    100 points: ~4.7 KB
    
    Complex object:
  10. self.name ← Alice, self.age ← 30, self.email ← alice@example.com

    73class PersonNoSlots:74    def __init__(self⟨PersonNoSlots KQ⟩, nameAlice, age30, emailalice@example.com, cityNYC):75        self.name→ Alice = nameAlice76        self.age→ 30 = age3077        self.email→ alice@example.com = emailalice@example.com78        self.city→ NYC = cityNYC
  11. p1 ← ⟨PersonNoSlots KQ⟩

    89p1→ ⟨PersonNoSlots KQ⟩ = PersonNoSlots("Alice", 30, "alice@example.com", "NYC")90p2 = PersonWithSlots("Alice", 30, "alice@example.com", "NYC")
  12. self.name ← Alice, self.age ← 30, self.email ← alice@example.com

    83def __init__(self⟨PersonWithSlots KR⟩, nameAlice, age30, emailalice@example.com, cityNYC):84    self.name→ Alice = nameAlice85    self.age→ 30 = age3086    self.email→ alice@example.com = emailalice@example.com87    self.city→ NYC = cityNYC
  13. p2 ← ⟨PersonWithSlots KR⟩, size1 ← 344, size2 ← 64, dataset_size ← 10000

    89p1 = PersonNoSlots("Alice", 30, "alice@example.com", "NYC")90p2→ ⟨PersonWithSlots KR⟩ = PersonWithSlots("Alice", 30, "alice@example.com", "NYC")9192size1→ 344 = sys<module 'sys' (built-in)>.getsizeof(p1⟨PersonNoSlots KQ⟩) + sys.getsizeof(p1.__dict__{'name': 'Alice', 'age': 30, 'email': 'alice@example.com', 'city': 'NYC'})93size2→ 64 = sys<module 'sys' (built-in)>.getsizeof(p2⟨PersonWithSlots KR⟩)9495print(f"PersonNoSlots: {size1344} bytes")96print(f"PersonWithSlots: {size264} bytes")97print(f"Savings per instance: {size1344 - size264} bytes")9899# Large dataset100print("\nLarge dataset:")101102class Record:103    __slots__ = ['id', 'timestamp', 'value', 'status']104    105    def __init__(self, id, timestamp, value, status):106        self.id = id107        self.timestamp = timestamp108        self.value = value109        self.status = status110111# Simulate large dataset112dataset_size→ 10000 = 10000113print(f"Creating {dataset_size10000} records...")114115# Estimate memory (based on sample)116sample = Record(1, 1234567890, 42.5, "active")117record_size = sys.getsizeof(sample)
    outputPersonNoSlots: 344 bytes
    PersonWithSlots: 64 bytes
    Savings per instance: 280 bytes
    
    Large dataset:
    Creating 10000 records...
  14. self.id ← 1, self.timestamp ← 1234567890, self.value ← 42.5, self.status ← active

    105def __init__(self⟨Record KS⟩, id1, timestamp1234567890, value42.5, statusactive):106    self.id→ 1 = id1107    self.timestamp→ 1234567890 = timestamp1234567890108    self.value→ 42.5 = value42.5109    self.status→ active = statusactive
  15. sample ← ⟨Record KS⟩, record_size ← 64, minutes_per_year ← 525600

    115# Estimate memory (based on sample)116sample→ ⟨Record KS⟩ = Record(1, 1234567890, 42.5, "active")117record_size→ 64 = sys<module 'sys' (built-in)>.getsizeof(sample⟨Record KS⟩)118119print(f"Size per record: {record_size64} bytes")120print(f"Total for {dataset_size10000} records: ~{record_size64 * dataset_size / 1024 / 1024:.1f} MB")121122# Time series data123print("\nTime series data:")124125class DataPoint:126    __slots__ = ['timestamp', 'value']127    128    def __init__(self, timestamp, value):129        self.timestamp = timestamp130        self.value = value131132# Simulate 1 year of per-minute data133minutes_per_year→ 525600 = 365 * 24 * 60134point_size = sys<module 'sys' (built-in)>.getsizeof(DataPoint(0, 0.0))
    outputSize per record: 64 bytes
    Total for 10000 records: ~0.6 MB
    
    Time series data:
  16. self.timestamp ← 0, self.value ← 0.0

    128def __init__(self⟨DataPoint KT⟩, timestamp0, value0.0):129    self.timestamp→ 0 = timestamp0130    self.value→ 0.0 = value0.0
  17. point_size ← 48, entity_count ← 1000

    133minutes_per_year = 365 * 24 * 60134point_size→ 48 = sys<module 'sys' (built-in)>.getsizeof(DataPoint(0, 0.0))135136print(f"Data point size: {point_size48} bytes")137print(f"1 year (minute resolution): ~{point_size48 * minutes_per_year525600 / 1024 / 1024:.1f} MB")138139# Practical comparison140print("\nPractical comparison:")141142# Coordinates for game143class CoordNoSlots:144    def __init__(self, x, y, z):145        self.x = x146        self.y = y147        self.z = z148149class CoordWithSlots:150    __slots__ = ['x', 'y', 'z']151    152    def __init__(self, x, y, z):153        self.x = x154        self.y = y155        self.z = z156157# Simulate game world with many entities158entity_count→ 1000 = 1000159160# Sample sizes161no_slots = CoordNoSlots(0, 0, 0)162with_slots = CoordWithSlots(0, 0, 0)
    outputData point size: 48 bytes
    1 year (minute resolution): ~24.1 MB
    
    Practical comparison:
  18. self.x ← 0, self.y ← 0, self.z ← 0

    143class CoordNoSlots:144    def __init__(self⟨CoordNoSlots KU⟩, x0, y0, z0):145        self.x→ 0 = x0146        self.y→ 0 = y0147        self.z→ 0 = z0
  19. no_slots ← ⟨CoordNoSlots KU⟩

    160# Sample sizes161no_slots→ ⟨CoordNoSlots KU⟩ = CoordNoSlots(0, 0, 0)162with_slots = CoordWithSlots(0, 0, 0)
  20. self.x ← 0, self.y ← 0, self.z ← 0

    152def __init__(self⟨CoordWithSlots KV⟩, x0, y0, z0):153    self.x→ 0 = x0154    self.y→ 0 = y0155    self.z→ 0 = z0
  21. with_slots ← ⟨CoordWithSlots KV⟩, size_no ← 344, size_with ← 56

    161no_slots = CoordNoSlots(0, 0, 0)162with_slots→ ⟨CoordWithSlots KV⟩ = CoordWithSlots(0, 0, 0)163164size_no→ 344 = sys<module 'sys' (built-in)>.getsizeof(no_slots⟨CoordNoSlots KU⟩) + sys.getsizeof(no_slots.__dict__{'x': 0, 'y': 0, 'z': 0})165size_with→ 56 = sys<module 'sys' (built-in)>.getsizeof(with_slots⟨CoordWithSlots KV⟩)166167print(f"{entity_count1000} game entities:")168print(f"Without __slots__: ~{size_no344 * entity_count1000 / 1024:.1f} KB")169print(f"With __slots__: ~{size_with56 * entity_count1000 / 1024:.1f} KB")170print(f"Memory saved: ~{(size_no344 - size_with56) * entity_count1000 / 1024:.1f} KB")
    output1000 game entities:
    Without __slots__: ~335.9 KB
    With __slots__: ~54.7 KB
    Memory saved: ~281.2 KB

The savings multiply quickly: 10,000 objects might save hundreds of kilobytes. For millions of objects, the difference can be gigabytes.

memory optimization The primary benefit of `__slots__` is reducing per-instance memory by ~40-50% for simple classes by eliminating the `__dict__` overhead.

No Dynamic Attributes

slots_no_dynamic_attrs.py
Replay: real traced execution (multi-file project)
"""No dynamic attributes with __slots__"""

# Dynamic attributes blocked
print("Dynamic attributes blocked:")

class User:
    __slots__ = ['name', 'email']

    def __init__(self, name, email):
        self.name = name
        self.email = email

user = User("Alice", "alice@example.com")

# Allowed attributes work
print(f"Name: {user.name}")
print(f"Email: {user.email}")

# Modifying allowed attributes works
user.name = "Alice Smith"
print(f"Updated name: {user.name}")

# Adding new attribute fails
try:
    user.age = 30
except AttributeError as e:
    print(f"Error adding 'age': {e}")

try:
    user.city = "NYC"
except AttributeError as e:
    print(f"Error adding 'city': {e}")

# No __dict__
print("\nNo __dict__:")

class NoDict:
    __slots__ = ['x', 'y']

    def __init__(self, x, y):
        self.x = x
        self.y = y

obj = NoDict(10, 20)

# __dict__ doesn't exist
print(f"Has __dict__: {hasattr(obj, '__dict__')}")

# Can't access __dict__
try:
    print(obj.__dict__)
except AttributeError as e:
    print(f"Error: {e}")

# __slots__ is available
print(f"__slots__: {obj.__slots__}")

# Deleting attributes
print("\nDeleting attributes:")

class Point:
    __slots__ = ['x', 'y']

    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(5, 10)
print(f"Point: ({p.x}, {p.y})")

# Can delete slotted attributes
del p.x
print(f"Has x: {hasattr(p, 'x')}")

# Accessing deleted attribute fails
try:
    print(p.x)
except AttributeError as e:
    print(f"Error: {e}")

# Can reassign
p.x = 15
print(f"Reassigned x: {p.x}")

# Class attributes still work
print("\nClass attributes still work:")

class Config:
    __slots__ = ['name']

    # Class attributes are fine
    DEFAULT_TIMEOUT = 30
    VERSION = "1.0"

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

config = Config("prod")
print(f"Instance name: {config.name}")
print(f"Class DEFAULT_TIMEOUT: {config.DEFAULT_TIMEOUT}")
print(f"Class VERSION: {config.VERSION}")

# Can modify class attributes
Config.VERSION = "1.1"
print(f"Updated VERSION: {config.VERSION}")

# Methods still work
print("\nMethods still work:")

class Rectangle:
    __slots__ = ['width', 'height']

    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

rect = Rectangle(10, 5)
print(f"Area: {rect.area()}")
print(f"Perimeter: {rect.perimeter()}")

# Properties work
print("\nProperties work:")

class Temperature:
    __slots__ = ['_celsius']

    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        self._celsius = value

    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32

temp = Temperature(25)
print(f"Celsius: {temp.celsius}")
print(f"Fahrenheit: {temp.fahrenheit}")

temp.celsius = 30
print(f"Updated - Celsius: {temp.celsius}, Fahrenheit: {temp.fahrenheit}")

# Weakref support
print("\nWeakref support:")

import weakref

# Without __weakref__ in __slots__, weakref fails
class NoWeakref:
    __slots__ = ['value']

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

obj1 = NoWeakref(42)

try:
    ref = weakref.ref(obj1)
except TypeError as e:
    print(f"Error without __weakref__: {e}")

# Add __weakref__ to support weak references
class WithWeakref:
    __slots__ = ['value', '__weakref__']

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

obj2 = WithWeakref(42)
ref = weakref.ref(obj2)
print(f"Weakref created: {ref()}")
print(f"Weakref value: {ref().value}")

# Pickle support
print("\nPickle support:")

import pickle

class PickleSlots:
    __slots__ = ['name', 'value']

    def __init__(self, name, value):
        self.name = name
        self.value = value

obj = PickleSlots("test", 123)

# Pickle and unpickle
pickled = pickle.dumps(obj)
restored = pickle.loads(pickled)

print(f"Original: {obj.name}, {obj.value}")
print(f"Restored: {restored.name}, {restored.value}")

# Practical example
print("\nPractical example:")

class ImmutablePoint:
    __slots__ = ['_x', '_y']

    def __init__(self, x, y):
        object.__setattr__(self, '_x', x)
        object.__setattr__(self, '_y', y)

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    def __setattr__(self, name, value):
        raise AttributeError(f"Cannot modify immutable attribute '{name}'")

    def __repr__(self):
        return f"ImmutablePoint({self._x}, {self._y})"

p = ImmutablePoint(10, 20)
print(f"Point: {p}")
print(f"x={p.x}, y={p.y}")

# Cannot modify
try:
    p.x = 30
except AttributeError as e:
    print(f"Error: {e}")

# Cannot add attributes
try:
    p.z = 40
except AttributeError as e:
    print(f"Error: {e}")

  1. """No dynamic attributes with __slots__"""

    1"""No dynamic attributes with __slots__"""23# Dynamic attributes blocked4print("Dynamic attributes blocked:")56class User:7    __slots__ = ['name', 'email']8    9    def __init__(self, name, email):10        self.name = name11        self.email = email1213user = User("Alice", "alice@example.com")
    outputDynamic attributes blocked:
  2. self.name ← Alice, self.email ← alice@example.com

    9def __init__(self⟨User A⟩, nameAlice, emailalice@example.com):10    self.name→ Alice = nameAlice11    self.email→ alice@example.com = emailalice@example.com
  3. user ← ⟨User A⟩, user.name ← Alice Smith

    13user→ ⟨User A⟩ = User("Alice", "alice@example.com")1415# Allowed attributes work16print(f"Name: {user.nameAlice}")17print(f"Email: {user.emailalice@example.com}")1819# Modifying allowed attributes works20user.name→ Alice Smith = "Alice Smith"21print(f"Updated name: {user.nameAlice Smith}")
    outputName: Alice
    Email: alice@example.com
    Updated name: Alice Smith
  4. except AttributeError as e:

    25    user.age = 3026except AttributeError as e:27    print(f"Error adding 'age': {e'User' object has no attribute 'age'}")
    outputError adding 'age': 'User' object has no attribute 'age'
  5. except AttributeError as e:

    30    user.city = "NYC"31except AttributeError as e:32    print(f"Error adding 'city': {e'User' object has no attribute 'city'}")
    outputError adding 'city': 'User' object has no attribute 'city'
  6. print(" No __dict__:")

    34# No __dict__35print("\nNo __dict__:")3637class NoDict:38    __slots__ = ['x', 'y']39    40    def __init__(self, x, y):41        self.x = x42        self.y = y4344obj = NoDict(10, 20)
    output
    No __dict__:
  7. self.x ← 10, self.y ← 20

    40def __init__(self⟨NoDict B⟩, x10, y20):41    self.x→ 10 = x1042    self.y→ 20 = y20
  8. obj ← ⟨NoDict B⟩

    44obj→ ⟨NoDict B⟩ = NoDict(10, 20)4546# __dict__ doesn't exist47print(f"Has __dict__: {hasattr(obj⟨NoDict B⟩, '__dict__')}")
    outputHas __dict__: False
  9. try:

    49# Can't access __dict__50try:51    print(obj.__dict__(empty))52except AttributeError as e:
  10. except AttributeError as e:

    51    print(obj.__dict__)52except AttributeError as e:53    print(f"Error: {e'NoDict' object has no attribute '__dict__'}")
    outputError: 'NoDict' object has no attribute '__dict__'
  11. print(f"__slots__: {obj.__slots__}")

    55# __slots__ is available56print(f"__slots__: {obj.__slots__['x', 'y']}")5758# Deleting attributes59print("\nDeleting attributes:")6061class Point:62    __slots__ = ['x', 'y']63    64    def __init__(self, x, y):65        self.x = x66        self.y = y6768p = Point(5, 10)69print(f"Point: ({p.x}, {p.y})")
    output__slots__: ['x', 'y']
    
    Deleting attributes:
  12. self.x ← 5, self.y ← 10

    64def __init__(self⟨Point C⟩, x5, y10):65    self.x→ 5 = x566    self.y→ 10 = y10
  13. p ← ⟨Point C⟩

    68p→ ⟨Point C⟩ = Point(5, 10)69print(f"Point: ({p.x5}, {p.y10})")7071# Can delete slotted attributes72del p.x73print(f"Has x: {hasattr(p⟨Point C⟩, 'x')}")
    outputPoint: (5, 10)
    Has x: False
  14. try:

    75# Accessing deleted attribute fails76try:77    print(p.x(empty))78except AttributeError as e:
  15. except AttributeError as e:

    77    print(p.x)78except AttributeError as e:79    print(f"Error: {e'Point' object has no attribute 'x'}")
    outputError: 'Point' object has no attribute 'x'
  16. p.x ← 15, DEFAULT_TIMEOUT ← (empty), VERSION ← (empty)

    81# Can reassign82p.x→ 15 = 1583print(f"Reassigned x: {p.x15}")8485# Class attributes still work86print("\nClass attributes still work:")8788class Config:89    __slots__ = ['name']90    91    # Class attributes are fine92    DEFAULT_TIMEOUT→ (empty) = 3093    VERSION→ (empty) = "1.0"94    95    def __init__(self, name):96        self.name = name9798config = Config("prod")99print(f"Instance name: {config.name}")
    outputReassigned x: 15
    
    Class attributes still work:
  17. self.name ← prod

    95def __init__(self⟨Config D⟩, nameprod):96    self.name→ prod = nameprod
  18. config ← ⟨Config D⟩, Config.VERSION ← 1.1

    98config→ ⟨Config D⟩ = Config("prod")99print(f"Instance name: {config.nameprod}")100print(f"Class DEFAULT_TIMEOUT: {config.DEFAULT_TIMEOUT30}")101print(f"Class VERSION: {config.VERSION1.0}")102103# Can modify class attributes104Config.VERSION→ 1.1 = "1.1"105print(f"Updated VERSION: {config.VERSION1.1}")106107# Methods still work108print("\nMethods still work:")109110class Rectangle:111    __slots__ = ['width', 'height']112    113    def __init__(self, width, height):114        self.width = width115        self.height = height116    117    def area(self):118        return self.width * self.height119    120    def perimeter(self):121        return 2 * (self.width + self.height)122123rect = Rectangle(10, 5)124print(f"Area: {rect.area()}")
    outputInstance name: prod
    Class DEFAULT_TIMEOUT: 30
    Class VERSION: 1.0
    Updated VERSION: 1.1
    
    Methods still work:
  19. self.width ← 10, self.height ← 5

    113def __init__(self⟨Rectangle E⟩, width10, height5):114    self.width→ 10 = width10115    self.height→ 5 = height5
  20. rect ← ⟨Rectangle E⟩

    123rect→ ⟨Rectangle E⟩ = Rectangle(10, 5)124print(f"Area: {rect⟨Rectangle E⟩.area()}")125print(f"Perimeter: {rect.perimeter()}")
  21. def area(self):

    117def area(self⟨Rectangle E⟩):118    return self.width10 * self.height5
  22. print(f"Area: {rect.area()}")

    123rect = Rectangle(10, 5)124print(f"Area: {rect⟨Rectangle E⟩.area()}")125print(f"Perimeter: {rect⟨Rectangle E⟩.perimeter()}")
    outputArea: 50
  23. def perimeter(self):

    120def perimeter(self⟨Rectangle E⟩):121    return 2 * (self.width10 + self.height5)
  24. print(f"Perimeter: {rect.perimeter()}")

    124print(f"Area: {rect.area()}")125print(f"Perimeter: {rect⟨Rectangle E⟩.perimeter()}")126127# Properties work128print("\nProperties work:")129130class Temperature:131    __slots__ = ['_celsius']132    133    def __init__(self, celsius):134        self._celsius = celsius135    136    @property137    def celsius(self):138        return self._celsius139    140    @celsius.setter141    def celsius(self, value):142        self._celsius = value143    144    @property145    def fahrenheit(self):146        return self._celsius * 9/5 + 32147148temp = Temperature(25)149print(f"Celsius: {temp.celsius}")
    outputPerimeter: 30
    
    Properties work:
  25. self._celsius ← 25

    133def __init__(self⟨Temperature F⟩, celsius25):134    self._celsius→ 25 = celsius25
  26. temp ← ⟨Temperature F⟩

    148temp→ ⟨Temperature F⟩ = Temperature(25)149print(f"Celsius: {temp.celsius25}")150print(f"Fahrenheit: {temp.fahrenheit}")
  27. def celsius(self):

    pass 1 of 2
    136@property137def celsius(self⟨Temperature F⟩):138    return self._celsius25
  28. print(f"Celsius: {temp.celsius}")

    148temp = Temperature(25)149print(f"Celsius: {temp.celsius25}")150print(f"Fahrenheit: {temp.fahrenheit77.0}")
    outputCelsius: 25
  29. def fahrenheit(self):

    pass 1 of 2
    144@property145def fahrenheit(self⟨Temperature F⟩):146    return self._celsius25 * 9/5 + 32
  30. print(f"Fahrenheit: {temp.fahrenheit}")

    149print(f"Celsius: {temp.celsius}")150print(f"Fahrenheit: {temp.fahrenheit77.0}")151152temp.celsius = 30153print(f"Updated - Celsius: {temp.celsius}, Fahrenheit: {temp.fahrenheit}")
    outputFahrenheit: 77.0
  31. self._celsius ← 30

    140@celsius.setter141def celsius(self⟨Temperature F⟩, value30):142    self._celsius→ 30 = value30
  32. temp.celsius ← 30

    152temp.celsius→ 30 = 30153print(f"Updated - Celsius: {temp.celsius30}, Fahrenheit: {temp.fahrenheit86.0}")
  33. def celsius(self):

    pass 2 of 2
    136@property137def celsius(self⟨Temperature F⟩):138    return self._celsius30
  34. def fahrenheit(self):

    pass 2 of 2
    144@property145def fahrenheit(self⟨Temperature F⟩):146    return self._celsius30 * 9/5 + 32
  35. print(f"Updated - Celsius: {temp.celsius}, Fahrenheit: {temp.fahrenhei…

    152temp.celsius = 30153print(f"Updated - Celsius: {temp.celsius30}, Fahrenheit: {temp.fahrenheit86.0}")154155# Weakref support156print("\nWeakref support:")157158import weakref159160# Without __weakref__ in __slots__, weakref fails161class NoWeakref:162    __slots__ = ['value']163    164    def __init__(self, value):165        self.value = value166167obj1 = NoWeakref(42)
    outputUpdated - Celsius: 30, Fahrenheit: 86.0
    
    Weakref support:
  36. self.value ← 42

    164def __init__(self⟨NoWeakref G⟩, value42):165    self.value→ 42 = value42
  37. obj1 ← ⟨NoWeakref G⟩

    167obj1→ ⟨NoWeakref G⟩ = NoWeakref(42)
  38. try:

    169try:170    ref = weakref<module 'weakref' from '/usr/local/lib/python3.12/weakref.py'>.ref(obj1⟨NoWeakref G⟩)171except TypeError as e:
  39. except TypeError as e:

    170    ref = weakref.ref(obj1)171except TypeError as e:172    print(f"Error without __weakref__: {ecannot create weak reference to 'NoWeakref' object}")
    outputError without __weakref__: cannot create weak reference to 'NoWeakref' object
  40. __slots__ = ['value', '__weakref__']

    175class WithWeakref:176    __slots__ = ['value', '__weakref__']177    178    def __init__(self, value):179        self.value = value180181obj2 = WithWeakref(42)182ref = weakref.ref(obj2)
  41. self.value ← 42

    178def __init__(self⟨WithWeakref H⟩, value42):179    self.value→ 42 = value42
  42. obj2 ← ⟨WithWeakref H⟩, ref ← ⟨weakref at ⟨addr I⟩; to 'WithWeakref' H⟩

    181obj2→ ⟨WithWeakref H⟩ = WithWeakref(42)182ref→ ⟨weakref at ⟨addr I⟩; to 'WithWeakref' H⟩ = weakref<module 'weakref' from '/usr/local/lib/python3.12/weakref.py'>.ref(obj2⟨WithWeakref H⟩)183print(f"Weakref created: {ref()}")184print(f"Weakref value: {ref().value}")185186# Pickle support187print("\nPickle support:")188189import pickle190191class PickleSlots:192    __slots__ = ['name', 'value']193    194    def __init__(self, name, value):195        self.name = name196        self.value = value197198obj = PickleSlots("test", 123)
    outputWeakref created: ⟨WithWeakref H⟩
    Weakref value: 42
    
    Pickle support:
  43. self.name ← test, self.value ← 123

    194def __init__(self⟨PickleSlots J⟩, nametest, value123):195    self.name→ test = nametest196    self.value→ 123 = value123
  44. obj ← ⟨PickleSlots J⟩, pickled ← b'\x80\x04\x95?\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x0bPickleSlots\x94\x93\x94)\x81\x94N}\x94(\x8c\x04name\x94\x8c\x04test\x94\x8c\x05value\x94K{u\x86\x94b.'

    198obj→ ⟨PickleSlots J⟩ = PickleSlots("test", 123)199200# Pickle and unpickle201pickled→ b'\x80\x04\x95?\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x0bPickleSlots\x94\x93\x94)\x81\x94N}\x94(\x8c\x04name\x94\x8c\x04test\x94\x8c\x05value\x94K{u\x86\x94b.' = pickle<module 'pickle' from '/usr/local/lib/python3.12/pickle.py'>.dumps(obj⟨PickleSlots J⟩)202restored→ ⟨PickleSlots B⟩ = pickle<module 'pickle' from '/usr/local/lib/python3.12/pickle.py'>.loads(pickledb'\x80\x04\x95?\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x0bPickleSlots\x94\x93\x94)\x81\x94N}\x94(\x8c\x04name\x94\x8c\x04test\x94\x8c\x05value\x94K{u\x86\x94b.')203204print(f"Original: {obj.nametest}, {obj.value123}")205print(f"Restored: {restored.nametest}, {restored.value123}")206207# Practical example208print("\nPractical example:")209210class ImmutablePoint:211    __slots__ = ['_x', '_y']212    213    def __init__(self, x, y):214        object.__setattr__(self, '_x', x)215        object.__setattr__(self, '_y', y)216    217    @property218    def x(self):219        return self._x220    221    @property222    def y(self):223        return self._y224    225    def __setattr__(self, name, value):226        raise AttributeError(f"Cannot modify immutable attribute '{name}'")227    228    def __repr__(self):229        return f"ImmutablePoint({self._x}, {self._y})"230231p = ImmutablePoint(10, 20)232print(f"Point: {p}")
    outputOriginal: test, 123
    Restored: test, 123
    
    Practical example:
  45. def __init__(self, x, y):

    213def __init__(self(empty), x10, y20):214    object.__setattr__(self, '_x', x10)215    object.__setattr__(self, '_y', y20)
  46. p ← ImmutablePoint(10, 20)

    231p→ ImmutablePoint(10, 20) = ImmutablePoint(10, 20)232print(f"Point: {pImmutablePoint(10, 20)}")233print(f"x={p.x10}, y={p.y20}")
    outputPoint: ImmutablePoint(10, 20)
  47. def x(self):

    217@property218def x(selfImmutablePoint(10, 20)):219    return self._x10
  48. def y(self):

    221@property222def y(selfImmutablePoint(10, 20)):223    return self._y20
  49. print(f"x={p.x}, y={p.y}")

    232print(f"Point: {p}")233print(f"x={p.x10}, y={p.y20}")
    outputx=10, y=20
  50. def __setattr__(self, name, value):

    pass 1 of 2
    225def __setattr__(selfImmutablePoint(10, 20), namex, value30):226    raise AttributeError(f"Cannot modify immutable attribute '{namex}'")
  51. except AttributeError as e:

    237    p.x = 30238except AttributeError as e:239    print(f"Error: {eCannot modify immutable attribute 'x'}")
    outputError: Cannot modify immutable attribute 'x'
  52. def __setattr__(self, name, value):

    pass 2 of 2
    225def __setattr__(selfImmutablePoint(10, 20), namez, value40):226    raise AttributeError(f"Cannot modify immutable attribute '{namez}'")
  53. except AttributeError as e:

    243    p.z = 40244except AttributeError as e:245    print(f"Error: {eCannot modify immutable attribute 'z'}")
    outputError: Cannot modify immutable attribute 'z'

This restriction is both a benefit (catches typos, enforces structure) and a limitation (no monkey-patching, no dynamic attributes).

attribute restriction With `__slots__`, attempting to add attributes not in the slots list raises an `AttributeError`, preventing typos and enforcing structure.

Inheritance with __slots__

slots_inheritance.py
Replay: real traced execution (multi-file project)
"""__slots__ with inheritance"""

# Basic inheritance
print("Basic inheritance:")

class Base:
    __slots__ = ['x']

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

class Derived(Base):
    __slots__ = ['y']  # Only add new slots

    def __init__(self, x, y):
        super().__init__(x)
        self.y = y

obj = Derived(10, 20)
print(f"x={obj.x}, y={obj.y}")
print(f"Base __slots__: {Base.__slots__}")
print(f"Derived __slots__: {Derived.__slots__}")

# Combined slots are inherited
try:
    obj.z = 30
except AttributeError as e:
    print(f"Error: {e}")

# Empty slots in derived
print("\nEmpty slots in derived:")

class BaseClass:
    __slots__ = ['a', 'b']

    def __init__(self, a, b):
        self.a = a
        self.b = b

class DerivedClass(BaseClass):
    __slots__ = []  # No new slots

    def method(self):
        return self.a + self.b

obj = DerivedClass(5, 10)
print(f"a={obj.a}, b={obj.b}")
print(f"method()={obj.method()}")

# Parent without __slots__
print("\nParent without __slots__:")

class ParentNoSlots:
    def __init__(self, x):
        self.x = x

class ChildWithSlots(ParentNoSlots):
    __slots__ = ['y']

    def __init__(self, x, y):
        super().__init__(x)
        self.y = y

obj = ChildWithSlots(10, 20)

# Parent has __dict__, child has slots
print(f"Has __dict__: {hasattr(obj, '__dict__')}")
print(f"__dict__: {obj.__dict__}")  # Contains parent attributes

# Can add attributes to parent's __dict__
obj.z = 30
print(f"Added z: {obj.z}")

# But child's slotted attributes are separate
print(f"y (slotted): {obj.y}")

# Child without __slots__
print("\nChild without __slots__:")

class ParentWithSlots:
    __slots__ = ['x']

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

class ChildNoSlots(ParentWithSlots):
    # No __slots__ means __dict__ is created
    def __init__(self, x, y):
        super().__init__(x)
        self.y = y  # Stored in __dict__

obj = ChildNoSlots(10, 20)
print(f"x (slotted): {obj.x}")
print(f"y (dict): {obj.y}")
print(f"Has __dict__: {hasattr(obj, '__dict__')}")

# Can add dynamic attributes
obj.z = 30
print(f"Added z: {obj.z}")

# Multiple inheritance
print("\nMultiple inheritance:")

class A:
    __slots__ = ['a']

class B(A):
    __slots__ = ['b']

class C(B):
    __slots__ = ['c']

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

obj = C(1, 2, 3)
print(f"a={obj.a}, b={obj.b}, c={obj.c}")

# Diamond inheritance
print("\nDiamond inheritance:")

class Base2:
    __slots__ = ['value']

class Left(Base2):
    __slots__ = ['left_value']

# For diamond to work, only one branch can have non-empty __slots__
class Right(Base2):
    __slots__ = []  # Empty slots - avoids layout conflict

class Diamond(Left, Right):
    __slots__ = ['diamond_value']

    def __init__(self, value, left, diamond):
        self.value = value
        self.left_value = left
        self.diamond_value = diamond

obj = Diamond(1, 2, 3)
print(f"value={obj.value}, left={obj.left_value}, diamond={obj.diamond_value}")

# Override with __dict__
print("\nOverride with __dict__:")

class Parent:
    __slots__ = ['x']

class Child(Parent):
    __slots__ = ['y', '__dict__']  # Add __dict__ explicitly

    def __init__(self, x, y):
        self.x = x
        self.y = y

obj = Child(10, 20)
print(f"x={obj.x}, y={obj.y}")

# Can now add dynamic attributes
obj.z = 30
print(f"Added z: {obj.z}")
print(f"__dict__: {obj.__dict__}")

# Mixin classes
print("\nMixin classes:")

class SlottedBase:
    __slots__ = ['id', 'name']

class Mixin:
    def get_info(self):
        return f"{self.name} (ID: {self.id})"

class ConcreteClass(SlottedBase, Mixin):
    __slots__ = ['email']

    def __init__(self, id, name, email):
        self.id = id
        self.name = name
        self.email = email

obj = ConcreteClass(1, "Alice", "alice@example.com")
print(f"Info: {obj.get_info()}")
print(f"Email: {obj.email}")

# Practical example
print("\nPractical example:")

# Shape hierarchy
class Shape:
    __slots__ = ['color']

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

class Circle(Shape):
    __slots__ = ['radius']

    def __init__(self, color, radius):
        super().__init__(color)
        self.radius = radius

    def area(self):
        import math
        return math.pi * self.radius ** 2

class Rectangle(Shape):
    __slots__ = ['width', 'height']

    def __init__(self, color, width, height):
        super().__init__(color)
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

circle = Circle("red", 5)
rectangle = Rectangle("blue", 10, 20)

print(f"Circle: color={circle.color}, radius={circle.radius}, area={circle.area():.2f}")
print(f"Rectangle: color={rectangle.color}, width={rectangle.width}, height={rectangle.height}, area={rectangle.area()}")

  1. """__slots__ with inheritance"""

    1"""__slots__ with inheritance"""23# Basic inheritance4print("Basic inheritance:")56class Base:7    __slots__ = ['x']8    9    def __init__(self, x):10        self.x = x1112class Derived(Base):13    __slots__ = ['y']  # Only add new slots14    15    def __init__(self, x, y):16        super().__init__(x)17        self.y = y1819obj = Derived(10, 20)20print(f"x={obj.x}, y={obj.y}")
    outputBasic inheritance:
  2. def __init__(self, x, y):

    15def __init__(self⟨Derived A⟩, x10, y20):16    super().__init__(x)17    self.y = y
  3. self.x ← 10

    9def __init__(self⟨Derived A⟩, x10):10    self.x→ 10 = x10
  4. self.y ← 20

    16super().__init__(x)17self.y→ 20 = y20
  5. obj ← ⟨Derived A⟩

    19obj→ ⟨Derived A⟩ = Derived(10, 20)20print(f"x={obj.x10}, y={obj.y20}")21print(f"Base __slots__: {Base.__slots__['x']}")22print(f"Derived __slots__: {Derived.__slots__['y']}")
    outputx=10, y=20
    Base __slots__: ['x']
    Derived __slots__: ['y']
  6. except AttributeError as e:

    26    obj.z = 3027except AttributeError as e:28    print(f"Error: {e'Derived' object has no attribute 'z'}")
    outputError: 'Derived' object has no attribute 'z'
  7. print(" Empty slots in derived:")

    30# Empty slots in derived31print("\nEmpty slots in derived:")3233class BaseClass:34    __slots__ = ['a', 'b']35    36    def __init__(self, a, b):37        self.a = a38        self.b = b3940class DerivedClass(BaseClass):41    __slots__ = []  # No new slots42    43    def method(self):44        return self.a + self.b4546obj = DerivedClass(5, 10)47print(f"a={obj.a}, b={obj.b}")
    output
    Empty slots in derived:
  8. self.a ← 5, self.b ← 10

    36def __init__(self⟨DerivedClass B⟩, a5, b10):37    self.a→ 5 = a538    self.b→ 10 = b10
  9. obj ← ⟨DerivedClass B⟩

    46obj→ ⟨DerivedClass B⟩ = DerivedClass(5, 10)47print(f"a={obj.a5}, b={obj.b10}")48print(f"method()={obj⟨DerivedClass B⟩.method()}")
    outputa=5, b=10
  10. def method(self):

    43def method(self⟨DerivedClass B⟩):44    return self.a5 + self.b10
  11. print(f"method()={obj.method()}")

    47print(f"a={obj.a}, b={obj.b}")48print(f"method()={obj⟨DerivedClass B⟩.method()}")4950# Parent without __slots__51print("\nParent without __slots__:")5253class ParentNoSlots:54    def __init__(self, x):55        self.x = x5657class ChildWithSlots(ParentNoSlots):58    __slots__ = ['y']59    60    def __init__(self, x, y):61        super().__init__(x)62        self.y = y6364obj = ChildWithSlots(10, 20)
    outputmethod()=15
    
    Parent without __slots__:
  12. def __init__(self, x, y):

    60def __init__(self⟨ChildWithSlots C⟩, x10, y20):61    super().__init__(x)62    self.y = y
  13. self.x ← 10

    53class ParentNoSlots:54    def __init__(self⟨ChildWithSlots C⟩, x10):55        self.x→ 10 = x10
  14. self.y ← 20

    61super().__init__(x)62self.y→ 20 = y20
  15. obj ← ⟨ChildWithSlots C⟩, obj.z ← 30

    64obj→ ⟨ChildWithSlots C⟩ = ChildWithSlots(10, 20)6566# Parent has __dict__, child has slots67print(f"Has __dict__: {hasattr(obj⟨ChildWithSlots C⟩, '__dict__')}")68print(f"__dict__: {obj.__dict__{'x': 10}}")  # Contains parent attributes6970# Can add attributes to parent's __dict__71obj.z→ 30 = 3072print(f"Added z: {obj.z30}")7374# But child's slotted attributes are separate75print(f"y (slotted): {obj.y20}")7677# Child without __slots__78print("\nChild without __slots__:")7980class ParentWithSlots:81    __slots__ = ['x']82    83    def __init__(self, x):84        self.x = x8586class ChildNoSlots(ParentWithSlots):87    # No __slots__ means __dict__ is created88    def __init__(self, x, y):89        super().__init__(x)90        self.y = y  # Stored in __dict__9192obj = ChildNoSlots(10, 20)93print(f"x (slotted): {obj.x}")
    outputHas __dict__: True
    __dict__: {'x': 10}
    Added z: 30
    y (slotted): 20
    
    Child without __slots__:
  16. def __init__(self, x, y):

    87# No __slots__ means __dict__ is created88def __init__(self⟨ChildNoSlots D⟩, x10, y20):89    super().__init__(x)90    self.y = y  # Stored in __dict__
  17. self.x ← 10

    83def __init__(self⟨ChildNoSlots D⟩, x10):84    self.x→ 10 = x10
  18. self.y ← 20

    89super().__init__(x)90self.y→ 20 = y20  # Stored in __dict__
  19. obj ← ⟨ChildNoSlots D⟩, obj.z ← 30

    92obj→ ⟨ChildNoSlots D⟩ = ChildNoSlots(10, 20)93print(f"x (slotted): {obj.x10}")94print(f"y (dict): {obj.y20}")95print(f"Has __dict__: {hasattr(obj⟨ChildNoSlots D⟩, '__dict__')}")9697# Can add dynamic attributes98obj.z→ 30 = 3099print(f"Added z: {obj.z30}")100101# Multiple inheritance102print("\nMultiple inheritance:")103104class A:105    __slots__ = ['a']106107class B(A):108    __slots__ = ['b']109110class C(B):111    __slots__ = ['c']112113    def __init__(self, a, b, c):114        self.a = a115        self.b = b116        self.c = c117118obj = C(1, 2, 3)119print(f"a={obj.a}, b={obj.b}, c={obj.c}")
    outputx (slotted): 10
    y (dict): 20
    Has __dict__: True
    Added z: 30
    
    Multiple inheritance:
  20. self.a ← 1, self.b ← 2, self.c ← 3

    113def __init__(self⟨C E⟩, a1, b2, c3):114    self.a→ 1 = a1115    self.b→ 2 = b2116    self.c→ 3 = c3
  21. obj ← ⟨C E⟩

    118obj→ ⟨C E⟩ = C(1, 2, 3)119print(f"a={obj.a1}, b={obj.b2}, c={obj.c3}")120121# Diamond inheritance122print("\nDiamond inheritance:")123124class Base2:125    __slots__ = ['value']126127class Left(Base2):128    __slots__ = ['left_value']129130# For diamond to work, only one branch can have non-empty __slots__131class Right(Base2):132    __slots__ = []  # Empty slots - avoids layout conflict133134class Diamond(Left, Right):135    __slots__ = ['diamond_value']136137    def __init__(self, value, left, diamond):138        self.value = value139        self.left_value = left140        self.diamond_value = diamond141142obj = Diamond(1, 2, 3)143print(f"value={obj.value}, left={obj.left_value}, diamond={obj.diamond_value}")
    outputa=1, b=2, c=3
    
    Diamond inheritance:
  22. self.value ← 1, self.left_value ← 2, self.diamond_value ← 3

    137def __init__(self⟨Diamond F⟩, value1, left2, diamond3):138    self.value→ 1 = value1139    self.left_value→ 2 = left2140    self.diamond_value→ 3 = diamond3
  23. obj ← ⟨Diamond F⟩

    142obj→ ⟨Diamond F⟩ = Diamond(1, 2, 3)143print(f"value={obj.value1}, left={obj.left_value2}, diamond={obj.diamond_value3}")144145# Override with __dict__146print("\nOverride with __dict__:")147148class Parent:149    __slots__ = ['x']150151class Child(Parent):152    __slots__ = ['y', '__dict__']  # Add __dict__ explicitly153    154    def __init__(self, x, y):155        self.x = x156        self.y = y157158obj = Child(10, 20)159print(f"x={obj.x}, y={obj.y}")
    outputvalue=1, left=2, diamond=3
    
    Override with __dict__:
  24. self.x ← 10, self.y ← 20

    154def __init__(self⟨Child G⟩, x10, y20):155    self.x→ 10 = x10156    self.y→ 20 = y20
  25. obj ← ⟨Child G⟩, obj.z ← 30

    158obj→ ⟨Child G⟩ = Child(10, 20)159print(f"x={obj.x10}, y={obj.y20}")160161# Can now add dynamic attributes162obj.z→ 30 = 30163print(f"Added z: {obj.z30}")164print(f"__dict__: {obj.__dict__{'z': 30}}")165166# Mixin classes167print("\nMixin classes:")168169class SlottedBase:170    __slots__ = ['id', 'name']171172class Mixin:173    def get_info(self):174        return f"{self.name} (ID: {self.id})"175176class ConcreteClass(SlottedBase, Mixin):177    __slots__ = ['email']178    179    def __init__(self, id, name, email):180        self.id = id181        self.name = name182        self.email = email183184obj = ConcreteClass(1, "Alice", "alice@example.com")185print(f"Info: {obj.get_info()}")
    outputx=10, y=20
    Added z: 30
    __dict__: {'z': 30}
    
    Mixin classes:
  26. self.id ← 1, self.name ← Alice, self.email ← alice@example.com

    179def __init__(self⟨ConcreteClass H⟩, id1, nameAlice, emailalice@example.com):180    self.id→ 1 = id1181    self.name→ Alice = nameAlice182    self.email→ alice@example.com = emailalice@example.com
  27. obj ← ⟨ConcreteClass H⟩

    184obj→ ⟨ConcreteClass H⟩ = ConcreteClass(1, "Alice", "alice@example.com")185print(f"Info: {obj⟨ConcreteClass H⟩.get_info()}")186print(f"Email: {obj.email}")
  28. def get_info(self):

    172class Mixin:173    def get_info(self⟨ConcreteClass H⟩):174        return f"{self.nameAlice} (ID: {self.id1})"
  29. print(f"Info: {obj.get_info()}")

    184obj = ConcreteClass(1, "Alice", "alice@example.com")185print(f"Info: {obj⟨ConcreteClass H⟩.get_info()}")186print(f"Email: {obj.emailalice@example.com}")187188# Practical example189print("\nPractical example:")190191# Shape hierarchy192class Shape:193    __slots__ = ['color']194    195    def __init__(self, color):196        self.color = color197198class Circle(Shape):199    __slots__ = ['radius']200    201    def __init__(self, color, radius):202        super().__init__(color)203        self.radius = radius204    205    def area(self):206        import math207        return math.pi * self.radius ** 2208209class Rectangle(Shape):210    __slots__ = ['width', 'height']211    212    def __init__(self, color, width, height):213        super().__init__(color)214        self.width = width215        self.height = height216    217    def area(self):218        return self.width * self.height219220circle = Circle("red", 5)221rectangle = Rectangle("blue", 10, 20)
    outputInfo: Alice (ID: 1)
    Email: alice@example.com
    
    Practical example:
  30. def __init__(self, color, radius):

    201def __init__(self⟨Circle I⟩, colorred, radius5):202    super().__init__(color)203    self.radius = radius
  31. self.color ← red

    pass 1 of 2
    195def __init__(self⟨Circle I⟩, colorred):196    self.color→ red = colorred
  32. self.radius ← 5

    202super().__init__(color)203self.radius→ 5 = radius5
  33. circle ← ⟨Circle I⟩

    220circle→ ⟨Circle I⟩ = Circle("red", 5)221rectangle = Rectangle("blue", 10, 20)
  34. def __init__(self, color, width, height):

    212def __init__(self⟨Rectangle J⟩, colorblue, width10, height20):213    super().__init__(color)214    self.width = width
  35. self.color ← blue

    pass 2 of 2
    195def __init__(self⟨Rectangle J⟩, colorblue):196    self.color→ blue = colorblue
  36. self.width ← 10, self.height ← 20

    213super().__init__(color)214self.width→ 10 = width10215self.height→ 20 = height20
  37. rectangle ← ⟨Rectangle J⟩

    220circle = Circle("red", 5)221rectangle→ ⟨Rectangle J⟩ = Rectangle("blue", 10, 20)222223print(f"Circle: color={circle.colorred}, radius={circle.radius5}, area={circle⟨Circle I⟩.area():.2f}")224print(f"Rectangle: color={rectangle.color}, width={rectangle.width}, height={rectangle.height}, area={rectangle.area()}")
  38. def area(self):

    205def area(self⟨Circle I⟩):206    import math207    return math.pi3.141592653589793 * self.radius5 ** 2
  39. print(f"Circle: color={circle.color}, radius={circle.radius}, area={ci…

    223print(f"Circle: color={circle.colorred}, radius={circle.radius5}, area={circle⟨Circle I⟩.area():.2f}")224print(f"Rectangle: color={rectangle.colorblue}, width={rectangle.width10}, height={rectangle.height20}, area={rectangle⟨Rectangle J⟩.area()}")
    outputCircle: color=red, radius=5, area=78.54
  40. def area(self):

    217def area(self⟨Rectangle J⟩):218    return self.width10 * self.height20
  41. print(f"Rectangle: color={rectangle.color}, width={rectangle.width}, h…

    223print(f"Circle: color={circle.color}, radius={circle.radius}, area={circle.area():.2f}")224print(f"Rectangle: color={rectangle.colorblue}, width={rectangle.width10}, height={rectangle.height20}, area={rectangle⟨Rectangle J⟩.area()}")
    outputRectangle: color=blue, width=10, height=20, area=200

Be careful: if any class in the hierarchy lacks __slots__, instances get a __dict__ and lose the memory benefits.

slots inheritance Child classes only need to define slots for their new attributes; they inherit parent slots automatically.

When to Use __slots__

slots_use_cases.py
Replay: real traced execution (multi-file project)
"""When to use __slots__"""

# When to use __slots__
print("When to use __slots__:")

# 1. Many instances
class Particle:
    __slots__ = ['x', 'y', 'vx', 'vy']

    def __init__(self, x, y, vx, vy):
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy

# Useful when creating thousands/millions
particles = [Particle(i, i*2, i*3, i*4) for i in range(100)]
print(f"✓ Good: Created {len(particles)} particles with __slots__")

# Fixed attributes
print("\nFixed attributes:")

class DatabaseRecord:
    __slots__ = ['id', 'timestamp', 'user_id', 'action', 'data']

    def __init__(self, id, timestamp, user_id, action, data):
        self.id = id
        self.timestamp = timestamp
        self.user_id = user_id
        self.action = action
        self.data = data

record = DatabaseRecord(1, 1234567890, 42, "login", {"ip": "127.0.0.1"})
print(f"✓ Good: Fixed schema prevents typos")

# Data classes
print("\nData classes:")

class Point3D:
    __slots__ = ['x', 'y', 'z']

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return f"Point3D({self.x}, {self.y}, {self.z})"

    def distance_from_origin(self):
        return (self.x**2 + self.y**2 + self.z**2) ** 0.5

p = Point3D(3, 4, 5)
print(f"✓ Good: Simple data container")
print(f"  Point: {p}, distance: {p.distance_from_origin():.2f}")

# When NOT to use __slots__
print("\nWhen NOT to use __slots__:")

# 1. Dynamic attributes needed
class FlexibleConfig:
    # Don't use __slots__ here
    def __init__(self):
        self.settings = {}

    def set(self, key, value):
        self.settings[key] = value

config = FlexibleConfig()
config.debug = True  # Need this flexibility
config.timeout = 30
print(f"✗ Bad for __slots__: Dynamic attributes needed")

# Few instances
print("\nFew instances:")

# Don't use __slots__ for singletons or few instances
class AppConfig:
    # No need for __slots__ - only one instance
    def __init__(self):
        self.host = "localhost"
        self.port = 8080
        self.debug = False

config = AppConfig()
print(f"✗ Bad for __slots__: Only a few instances")

# Complex inheritance
print("\nComplex inheritance:")

# Avoid __slots__ with complex inheritance hierarchies
class Base:
    def __init__(self):
        self.base_attr = "base"

class Mixin1:
    def method1(self):
        return "mixin1"

class Mixin2:
    def method2(self):
        return "mixin2"

class ComplexClass(Base, Mixin1, Mixin2):
    # Don't add __slots__ here - too complex
    def __init__(self):
        super().__init__()
        self.extra = "extra"

obj = ComplexClass()
print(f"✗ Bad for __slots__: Complex inheritance")

# Performance-critical code
print("\nPerformance-critical code:")

class Vector:
    __slots__ = ['x', 'y']

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def dot(self, other):
        return self.x * other.x + self.y * other.y

# Good for tight loops
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(f"✓ Good: Performance-critical math operations")

# Large collections
print("\nLarge collections:")

class LogEntry:
    __slots__ = ['timestamp', 'level', 'message']

    def __init__(self, timestamp, level, message):
        self.timestamp = timestamp
        self.level = level
        self.message = message

# Good for storing millions of log entries in memory
logs = [LogEntry(i, "INFO", f"Message {i}") for i in range(100)]
print(f"✓ Good: Large collections ({len(logs)} entries)")

# Embedded systems
print("\nEmbedded systems:")

class SensorReading:
    __slots__ = ['sensor_id', 'value', 'unit']

    def __init__(self, sensor_id, value, unit):
        self.sensor_id = sensor_id
        self.value = value
        self.unit = unit

reading = SensorReading(1, 23.5, "C")
print(f"✓ Good: Memory-constrained environments")

# Game development
print("\nGame development:")

class Entity:
    __slots__ = ['id', 'x', 'y', 'sprite', 'health']

    def __init__(self, id, x, y, sprite, health):
        self.id = id
        self.x = x
        self.y = y
        self.sprite = sprite
        self.health = health

# Good for thousands of game entities
entities = [Entity(i, i*10, i*20, f"sprite{i}", 100) for i in range(100)]
print(f"✓ Good: Game with {len(entities)} entities")

# Practical decision guide
print("\nPractical decision guide:")

print("\nUse __slots__ when:")
print("  ✓ Creating many instances (>1000)")
print("  ✓ Attributes are fixed and known")
print("  ✓ Memory is constrained")
print("  ✓ Attribute access speed matters")
print("  ✓ Preventing attribute typos is valuable")

print("\nAvoid __slots__ when:")
print("  ✗ Dynamic attributes are needed")
print("  ✗ Only a few instances exist")
print("  ✗ Complex inheritance hierarchies")
print("  ✗ Need __dict__ for introspection")
print("  ✗ Using libraries that expect __dict__")

# Real-world example
print("\nReal-world example:")

# Time series data storage
class TimeSeriesPoint:
    __slots__ = ['timestamp', 'value']

    def __init__(self, timestamp, value):
        self.timestamp = timestamp
        self.value = value

# Simulate 1 day of per-second data
seconds_per_day = 86400
timeseries = [TimeSeriesPoint(i, i * 0.1) for i in range(100)]  # Sample

print(f"✓ Excellent use case: Time series with {len(timeseries)} data points")
print(f"  Each point: timestamp + value")
print(f"  Fixed schema, many instances, memory-efficient")

  1. """When to use __slots__"""

    1"""When to use __slots__"""23# When to use __slots__4print("When to use __slots__:")56# 1. Many instances7class Particle:8    __slots__ = ['x', 'y', 'vx', 'vy']9    10    def __init__(self, x, y, vx, vy):11        self.x = x12        self.y = y13        self.vx = vx14        self.vy = vy1516# Useful when creating thousands/millions17particles = [Particle(i, i*2, i*3, i*4) for i in range(100)]18print(f"✓ Good: Created {len(particles)} particles with __slots__")
    outputWhen to use __slots__:
  2. self.x ← 0, self.y ← 0, self.vx ← 0, self.vy ← 0

    pass 1 of 100
    10def __init__(self⟨Particle A⟩, x0, y0, vx0, vy0):11    self.x→ 0 = x012    self.y→ 0 = y013    self.vx→ 0 = vx014    self.vy→ 0 = vy0
    100 passes — pass 1 is the card above
    passselfxyvxvyself.xself.yself.vxself.vy
    1⟨Particle A⟩00000000
    2⟨Particle B⟩12341234
    3⟨Particle C⟩24682468
    4⟨Particle D⟩3691236912
    5⟨Particle E⟩481216481216
    6⟨Particle F⟩51015205101520
    7⟨Particle G⟩61218246121824
    8⟨Particle H⟩71421287142128
    9⟨Particle I⟩81624328162432
    ⋯ 89 more passes ⋯
    99⟨Particle J⟩9819629439298196294392
    100⟨Particle K⟩9919829739699198297396
  3. particles ← [⟨Particle A⟩, ⟨Particle B⟩, ⟨Particle C⟩, ⟨Particle D⟩, ⟨Particle E⟩, ⟨Particle F⟩, ⟨Particle G⟩, ⟨Particle H⟩, ⟨Particle I⟩, ⟨Particle L⟩, ⟨Particle M⟩, ⟨Particle N⟩, ⟨Particle O⟩, ⟨Particle P⟩, ⟨Particle Q⟩, ⟨Particle R⟩, ⟨Particle S⟩, ⟨Particle T⟩, ⟨Particle U⟩, ⟨Particle V⟩, ⟨Particle W⟩, ⟨Particle X⟩, ⟨Particle Y⟩, ⟨Particle Z⟩, ⟨Particle AA⟩, ⟨Particle AB⟩, ⟨Particle AC⟩, ⟨Particle AD⟩, ⟨Particle AE⟩, ⟨Particle AF⟩, ⟨Particle AG⟩, ⟨Particle AH⟩, ⟨Particle AI⟩, ⟨Particle AJ⟩, ⟨Particle AK⟩, ⟨Particle AL⟩, ⟨Particle AM⟩, ⟨Particle AN⟩, ⟨Particle AO⟩, ⟨Particle AP⟩, ⟨Particle AQ⟩, ⟨Particle AR⟩, ⟨Particle AS⟩, ⟨Particle AT⟩, ⟨Particle AU⟩, ⟨Particle AV⟩, ⟨Particle AW⟩, ⟨Particle AX⟩, ⟨Particle AY⟩, ⟨Particle AZ⟩, ⟨Particle BA⟩, ⟨Particle BB⟩, ⟨Particle BC⟩, ⟨Particle BD⟩, ⟨Particle BE⟩, ⟨Particle BF⟩, ⟨Particle BG⟩, ⟨Particle BH⟩, ⟨Particle BI⟩, ⟨Particle BJ⟩, ⟨Particle BK⟩, ⟨Particle BL⟩, ⟨Particle BM⟩, ⟨Particle BN⟩, ⟨Particle BO⟩, ⟨Particle BP⟩, ⟨Particle BQ⟩, ⟨Particle BR⟩, ⟨Particle BS⟩, ⟨Particle BT⟩, ⟨Particle BU⟩, ⟨Particle BV⟩, ⟨Particle BW⟩, ⟨Particle BX⟩, ⟨Particle BY⟩, ⟨Particle BZ⟩, ⟨Particle CA⟩, ⟨Particle CB⟩, ⟨Particle CC⟩, ⟨Particle CD⟩, ⟨Particle CE⟩, ⟨Particle CF⟩, ⟨Particle CG⟩, ⟨Particle CH⟩, ⟨Particle CI⟩, ⟨Particle CJ⟩, ⟨Particle CK⟩, ⟨Particle CL⟩, ⟨Particle CM⟩, ⟨Particle CN⟩, ⟨Particle CO⟩, ⟨Particle CP⟩, ⟨Particle CQ⟩, ⟨Particle CR⟩, ⟨Particle CS⟩, ⟨Particle CT⟩, ⟨Particle CU⟩, ⟨Particle CV⟩, ⟨Particle J⟩, ⟨Particle K⟩]

    16# Useful when creating thousands/millions17particles→ [⟨Particle A⟩, ⟨Particle B⟩, ⟨Particle C⟩, ⟨Particle D⟩, ⟨Particle E⟩, ⟨Particle F⟩, ⟨Particle G⟩, ⟨Particle H⟩, ⟨Particle I⟩, ⟨Particle L⟩, ⟨Particle M⟩, ⟨Particle N⟩, ⟨Particle O⟩, ⟨Particle P⟩, ⟨Particle Q⟩, ⟨Particle R⟩, ⟨Particle S⟩, ⟨Particle T⟩, ⟨Particle U⟩, ⟨Particle V⟩, ⟨Particle W⟩, ⟨Particle X⟩, ⟨Particle Y⟩, ⟨Particle Z⟩, ⟨Particle AA⟩, ⟨Particle AB⟩, ⟨Particle AC⟩, ⟨Particle AD⟩, ⟨Particle AE⟩, ⟨Particle AF⟩, ⟨Particle AG⟩, ⟨Particle AH⟩, ⟨Particle AI⟩, ⟨Particle AJ⟩, ⟨Particle AK⟩, ⟨Particle AL⟩, ⟨Particle AM⟩, ⟨Particle AN⟩, ⟨Particle AO⟩, ⟨Particle AP⟩, ⟨Particle AQ⟩, ⟨Particle AR⟩, ⟨Particle AS⟩, ⟨Particle AT⟩, ⟨Particle AU⟩, ⟨Particle AV⟩, ⟨Particle AW⟩, ⟨Particle AX⟩, ⟨Particle AY⟩, ⟨Particle AZ⟩, ⟨Particle BA⟩, ⟨Particle BB⟩, ⟨Particle BC⟩, ⟨Particle BD⟩, ⟨Particle BE⟩, ⟨Particle BF⟩, ⟨Particle BG⟩, ⟨Particle BH⟩, ⟨Particle BI⟩, ⟨Particle BJ⟩, ⟨Particle BK⟩, ⟨Particle BL⟩, ⟨Particle BM⟩, ⟨Particle BN⟩, ⟨Particle BO⟩, ⟨Particle BP⟩, ⟨Particle BQ⟩, ⟨Particle BR⟩, ⟨Particle BS⟩, ⟨Particle BT⟩, ⟨Particle BU⟩, ⟨Particle BV⟩, ⟨Particle BW⟩, ⟨Particle BX⟩, ⟨Particle BY⟩, ⟨Particle BZ⟩, ⟨Particle CA⟩, ⟨Particle CB⟩, ⟨Particle CC⟩, ⟨Particle CD⟩, ⟨Particle CE⟩, ⟨Particle CF⟩, ⟨Particle CG⟩, ⟨Particle CH⟩, ⟨Particle CI⟩, ⟨Particle CJ⟩, ⟨Particle CK⟩, ⟨Particle CL⟩, ⟨Particle CM⟩, ⟨Particle CN⟩, ⟨Particle CO⟩, ⟨Particle CP⟩, ⟨Particle CQ⟩, ⟨Particle CR⟩, ⟨Particle CS⟩, ⟨Particle CT⟩, ⟨Particle CU⟩, ⟨Particle CV⟩, ⟨Particle J⟩, ⟨Particle K⟩] = [Particle(i, i*2, i*3, i*4) for i in range(100)]18print(f"✓ Good: Created {len(particles[⟨Particle A⟩, ⟨Particle B⟩, ⟨Particle C⟩, ⟨Particle D⟩, ⟨Particle E⟩, ⟨Particle F⟩, ⟨Particle G⟩, ⟨Particle H⟩, ⟨Particle I⟩, ⟨Particle L⟩, ⟨Particle M⟩, ⟨Particle N⟩, ⟨Particle O⟩, ⟨Particle P⟩, ⟨Particle Q⟩, ⟨Particle R⟩, ⟨Particle S⟩, ⟨Particle T⟩, ⟨Particle U⟩, ⟨Particle V⟩, ⟨Particle W⟩, ⟨Particle X⟩, ⟨Particle Y⟩, ⟨Particle Z⟩, ⟨Particle AA⟩, ⟨Particle AB⟩, ⟨Particle AC⟩, ⟨Particle AD⟩, ⟨Particle AE⟩, ⟨Particle AF⟩, ⟨Particle AG⟩, ⟨Particle AH⟩, ⟨Particle AI⟩, ⟨Particle AJ⟩, ⟨Particle AK⟩, ⟨Particle AL⟩, ⟨Particle AM⟩, ⟨Particle AN⟩, ⟨Particle AO⟩, ⟨Particle AP⟩, ⟨Particle AQ⟩, ⟨Particle AR⟩, ⟨Particle AS⟩, ⟨Particle AT⟩, ⟨Particle AU⟩, ⟨Particle AV⟩, ⟨Particle AW⟩, ⟨Particle AX⟩, ⟨Particle AY⟩, ⟨Particle AZ⟩, ⟨Particle BA⟩, ⟨Particle BB⟩, ⟨Particle BC⟩, ⟨Particle BD⟩, ⟨Particle BE⟩, ⟨Particle BF⟩, ⟨Particle BG⟩, ⟨Particle BH⟩, ⟨Particle BI⟩, ⟨Particle BJ⟩, ⟨Particle BK⟩, ⟨Particle BL⟩, ⟨Particle BM⟩, ⟨Particle BN⟩, ⟨Particle BO⟩, ⟨Particle BP⟩, ⟨Particle BQ⟩, ⟨Particle BR⟩, ⟨Particle BS⟩, ⟨Particle BT⟩, ⟨Particle BU⟩, ⟨Particle BV⟩, ⟨Particle BW⟩, ⟨Particle BX⟩, ⟨Particle BY⟩, ⟨Particle BZ⟩, ⟨Particle CA⟩, ⟨Particle CB⟩, ⟨Particle CC⟩, ⟨Particle CD⟩, ⟨Particle CE⟩, ⟨Particle CF⟩, ⟨Particle CG⟩, ⟨Particle CH⟩, ⟨Particle CI⟩, ⟨Particle CJ⟩, ⟨Particle CK⟩, ⟨Particle CL⟩, ⟨Particle CM⟩, ⟨Particle CN⟩, ⟨Particle CO⟩, ⟨Particle CP⟩, ⟨Particle CQ⟩, ⟨Particle CR⟩, ⟨Particle CS⟩, ⟨Particle CT⟩, ⟨Particle CU⟩, ⟨Particle CV⟩, ⟨Particle J⟩, ⟨Particle K⟩])} particles with __slots__")1920# Fixed attributes21print("\nFixed attributes:")2223class DatabaseRecord:24    __slots__ = ['id', 'timestamp', 'user_id', 'action', 'data']
    output✓ Good: Created 100 particles with __slots__
    
    Fixed attributes:
  4. self.id ← 1, self.timestamp ← 1234567890, self.user_id ← 42, self.action ← login

    26def __init__(self⟨DatabaseRecord CW⟩, id1, timestamp1234567890, user_id42, actionlogin, data{'ip': '127.0.0.1'}):27    self.id→ 1 = id128    self.timestamp→ 1234567890 = timestamp123456789029    self.user_id→ 42 = user_id4230    self.action→ login = actionlogin31    self.data→ {'ip': '127.0.0.1'} = data{'ip': '127.0.0.1'}
  5. print(f"✓ Good: Fixed schema prevents typos")

    33record = DatabaseRecord(1, 1234567890, 42, "login", {"ip": "127.0.0.1"})34print(f"✓ Good: Fixed schema prevents typos")3536# Data classes37print("\nData classes:")3839class Point3D:40    __slots__ = ['x', 'y', 'z']41    42    def __init__(self, x, y, z):43        self.x = x44        self.y = y45        self.z = z46    47    def __repr__(self):48        return f"Point3D({self.x}, {self.y}, {self.z})"49    50    def distance_from_origin(self):51        return (self.x**2 + self.y**2 + self.z**2) ** 0.55253p = Point3D(3, 4, 5)54print(f"✓ Good: Simple data container")
    output✓ Good: Fixed schema prevents typos
    
    Data classes:
  6. self.x ← 3, self.y ← 4, self.z ← 5

    42def __init__(self(empty), x3, y4, z5):43    self.x→ 3 = x344    self.y→ 4 = y445    self.z→ 5 = z5
  7. p ← Point3D(3, 4, 5)

    53p→ Point3D(3, 4, 5) = Point3D(3, 4, 5)54print(f"✓ Good: Simple data container")55print(f"  Point: {pPoint3D(3, 4, 5)}, distance: {p.distance_from_origin():.2f}")
    output✓ Good: Simple data container
  8. def distance_from_origin(self):

    50def distance_from_origin(selfPoint3D(3, 4, 5)):51    return (self.x3**2 + self.y4**2 + self.z5**2) ** 0.5
  9. print(f" Point: {p}, distance: {p.distance_from_origin():.2f}")

    54print(f"✓ Good: Simple data container")55print(f"  Point: {pPoint3D(3, 4, 5)}, distance: {p.distance_from_origin():.2f}")5657# When NOT to use __slots__58print("\nWhen NOT to use __slots__:")5960# 1. Dynamic attributes needed61class FlexibleConfig:62    # Don't use __slots__ here63    def __init__(self):64        self.settings = {}65    66    def set(self, key, value):67        self.settings[key] = value6869config = FlexibleConfig()70config.debug = True  # Need this flexibility
    output  Point: Point3D(3, 4, 5), distance: 7.07
    
    When NOT to use __slots__:
  10. self.settings ← {}

    62# Don't use __slots__ here63def __init__(self⟨FlexibleConfig CX⟩):64    self.settings→ {} = {}
  11. config ← ⟨FlexibleConfig CX⟩, config.debug ← True, config.timeout ← 30

    69config→ ⟨FlexibleConfig CX⟩ = FlexibleConfig()70config.debug→ True = True  # Need this flexibility71config.timeout→ 30 = 3072print(f"✗ Bad for __slots__: Dynamic attributes needed")7374# Few instances75print("\nFew instances:")7677# Don't use __slots__ for singletons or few instances78class AppConfig:79    # No need for __slots__ - only one instance80    def __init__(self):81        self.host = "localhost"82        self.port = 808083        self.debug = False8485config = AppConfig()86print(f"✗ Bad for __slots__: Only a few instances")
    output✗ Bad for __slots__: Dynamic attributes needed
    
    Few instances:
  12. self.host ← localhost, self.port ← 8080, self.debug ← False

    79# No need for __slots__ - only one instance80def __init__(self⟨AppConfig CY⟩):81    self.host→ localhost = "localhost"82    self.port→ 8080 = 808083    self.debug→ False = False
  13. config ← ⟨AppConfig CY⟩

    85config→ ⟨AppConfig CY⟩ = AppConfig()86print(f"✗ Bad for __slots__: Only a few instances")8788# Complex inheritance89print("\nComplex inheritance:")9091# Avoid __slots__ with complex inheritance hierarchies92class Base:93    def __init__(self):94        self.base_attr = "base"9596class Mixin1:97    def method1(self):98        return "mixin1"99100class Mixin2:101    def method2(self):102        return "mixin2"103104class ComplexClass(Base, Mixin1, Mixin2):105    # Don't add __slots__ here - too complex106    def __init__(self):107        super().__init__()108        self.extra = "extra"109110obj = ComplexClass()111print(f"✗ Bad for __slots__: Complex inheritance")
    output✗ Bad for __slots__: Only a few instances
    
    Complex inheritance:
  14. def __init__(self):

    105# Don't add __slots__ here - too complex106def __init__(self⟨ComplexClass CZ⟩):107    super().__init__()108    self.extra = "extra"
  15. self.base_attr ← base

    92class Base:93    def __init__(self⟨ComplexClass CZ⟩):94        self.base_attr→ base = "base"
  16. self.extra ← extra

    107super().__init__()108self.extra→ extra = "extra"
  17. obj ← ⟨ComplexClass CZ⟩

    110obj→ ⟨ComplexClass CZ⟩ = ComplexClass()111print(f"✗ Bad for __slots__: Complex inheritance")112113# Performance-critical code114print("\nPerformance-critical code:")115116class Vector:117    __slots__ = ['x', 'y']118    119    def __init__(self, x, y):120        self.x = x121        self.y = y122    123    def __add__(self, other):124        return Vector(self.x + other.x, self.y + other.y)125    126    def dot(self, other):127        return self.x * other.x + self.y * other.y128129# Good for tight loops130v1 = Vector(1, 2)131v2 = Vector(3, 4)
    output✗ Bad for __slots__: Complex inheritance
    
    Performance-critical code:
  18. self.x ← 1, self.y ← 2

    pass 1 of 2
    119def __init__(self⟨Vector DA⟩, x1, y2):120    self.x→ 1 = x1121    self.y→ 2 = y2
  19. v1 ← ⟨Vector DA⟩

    129# Good for tight loops130v1→ ⟨Vector DA⟩ = Vector(1, 2)131v2 = Vector(3, 4)132print(f"✓ Good: Performance-critical math operations")
  20. self.x ← 3, self.y ← 4

    pass 2 of 2
    119def __init__(self⟨Vector DB⟩, x3, y4):120    self.x→ 3 = x3121    self.y→ 4 = y4
  21. v2 ← ⟨Vector DB⟩

    130v1 = Vector(1, 2)131v2→ ⟨Vector DB⟩ = Vector(3, 4)132print(f"✓ Good: Performance-critical math operations")133134# Large collections135print("\nLarge collections:")136137class LogEntry:138    __slots__ = ['timestamp', 'level', 'message']139    140    def __init__(self, timestamp, level, message):141        self.timestamp = timestamp142        self.level = level143        self.message = message144145# Good for storing millions of log entries in memory146logs = [LogEntry(i, "INFO", f"Message {i}") for i in range(100)]147print(f"✓ Good: Large collections ({len(logs)} entries)")
    output✓ Good: Performance-critical math operations
    
    Large collections:
  22. self.timestamp ← 0, self.level ← INFO, self.message ← Message 0

    pass 1 of 100
    140def __init__(self⟨LogEntry DC⟩, timestamp0, levelINFO, messageMessage 0):141    self.timestamp→ 0 = timestamp0142    self.level→ INFO = levelINFO143    self.message→ Message 0 = messageMessage 0
    100 passes — pass 1 is the card above
    passselftimestampmessageself.timestampself.levelself.message
    1⟨LogEntry DC⟩0Message 00INFOMessage 0
    2⟨LogEntry DD⟩1Message 11INFOMessage 1
    3⟨LogEntry DE⟩2Message 22INFOMessage 2
    4⟨LogEntry DF⟩3Message 33INFOMessage 3
    5⟨LogEntry DG⟩4Message 44INFOMessage 4
    6⟨LogEntry DH⟩5Message 55INFOMessage 5
    7⟨LogEntry DI⟩6Message 66INFOMessage 6
    8⟨LogEntry DJ⟩7Message 77INFOMessage 7
    9⟨LogEntry DK⟩8Message 88INFOMessage 8
    ⋯ 89 more passes ⋯
    99⟨LogEntry DL⟩98Message 9898INFOMessage 98
    100⟨LogEntry DM⟩99Message 9999INFOMessage 99
  23. logs ← [⟨LogEntry DC⟩, ⟨LogEntry DD⟩, ⟨LogEntry DE⟩, ⟨LogEntry DF⟩, ⟨LogEntry DG⟩, ⟨LogEntry DH⟩, ⟨LogEntry DI⟩, ⟨LogEntry DJ⟩, ⟨LogEntry DK⟩, ⟨LogEntry DN⟩, ⟨LogEntry DO⟩, ⟨LogEntry DP⟩, ⟨LogEntry DQ⟩, ⟨LogEntry DR⟩, ⟨LogEntry DS⟩, ⟨LogEntry DT⟩, ⟨LogEntry DU⟩, ⟨LogEntry DV⟩, ⟨LogEntry DW⟩, ⟨LogEntry DX⟩, ⟨LogEntry DY⟩, ⟨LogEntry DZ⟩, ⟨LogEntry EA⟩, ⟨LogEntry EB⟩, ⟨LogEntry EC⟩, ⟨LogEntry ED⟩, ⟨LogEntry EE⟩, ⟨LogEntry EF⟩, ⟨LogEntry EG⟩, ⟨LogEntry EH⟩, ⟨LogEntry EI⟩, ⟨LogEntry EJ⟩, ⟨LogEntry EK⟩, ⟨LogEntry EL⟩, ⟨LogEntry EM⟩, ⟨LogEntry EN⟩, ⟨LogEntry EO⟩, ⟨LogEntry EP⟩, ⟨LogEntry EQ⟩, ⟨LogEntry ER⟩, ⟨LogEntry ES⟩, ⟨LogEntry ET⟩, ⟨LogEntry EU⟩, ⟨LogEntry EV⟩, ⟨LogEntry EW⟩, ⟨LogEntry EX⟩, ⟨LogEntry EY⟩, ⟨LogEntry EZ⟩, ⟨LogEntry FA⟩, ⟨LogEntry FB⟩, ⟨LogEntry FC⟩, ⟨LogEntry FD⟩, ⟨LogEntry FE⟩, ⟨LogEntry FF⟩, ⟨LogEntry FG⟩, ⟨LogEntry FH⟩, ⟨LogEntry FI⟩, ⟨LogEntry FJ⟩, ⟨LogEntry FK⟩, ⟨LogEntry FL⟩, ⟨LogEntry FM⟩, ⟨LogEntry FN⟩, ⟨LogEntry FO⟩, ⟨LogEntry FP⟩, ⟨LogEntry FQ⟩, ⟨LogEntry FR⟩, ⟨LogEntry FS⟩, ⟨LogEntry FT⟩, ⟨LogEntry FU⟩, ⟨LogEntry FV⟩, ⟨LogEntry FW⟩, ⟨LogEntry FX⟩, ⟨LogEntry FY⟩, ⟨LogEntry FZ⟩, ⟨LogEntry GA⟩, ⟨LogEntry GB⟩, ⟨LogEntry GC⟩, ⟨LogEntry GD⟩, ⟨LogEntry GE⟩, ⟨LogEntry GF⟩, ⟨LogEntry GG⟩, ⟨LogEntry GH⟩, ⟨LogEntry GI⟩, ⟨LogEntry GJ⟩, ⟨LogEntry GK⟩, ⟨LogEntry GL⟩, ⟨LogEntry GM⟩, ⟨LogEntry GN⟩, ⟨LogEntry GO⟩, ⟨LogEntry GP⟩, ⟨LogEntry GQ⟩, ⟨LogEntry GR⟩, ⟨LogEntry GS⟩, ⟨LogEntry GT⟩, ⟨LogEntry GU⟩, ⟨LogEntry GV⟩, ⟨LogEntry GW⟩, ⟨LogEntry GX⟩, ⟨LogEntry DL⟩, ⟨LogEntry DM⟩]

    145# Good for storing millions of log entries in memory146logs→ [⟨LogEntry DC⟩, ⟨LogEntry DD⟩, ⟨LogEntry DE⟩, ⟨LogEntry DF⟩, ⟨LogEntry DG⟩, ⟨LogEntry DH⟩, ⟨LogEntry DI⟩, ⟨LogEntry DJ⟩, ⟨LogEntry DK⟩, ⟨LogEntry DN⟩, ⟨LogEntry DO⟩, ⟨LogEntry DP⟩, ⟨LogEntry DQ⟩, ⟨LogEntry DR⟩, ⟨LogEntry DS⟩, ⟨LogEntry DT⟩, ⟨LogEntry DU⟩, ⟨LogEntry DV⟩, ⟨LogEntry DW⟩, ⟨LogEntry DX⟩, ⟨LogEntry DY⟩, ⟨LogEntry DZ⟩, ⟨LogEntry EA⟩, ⟨LogEntry EB⟩, ⟨LogEntry EC⟩, ⟨LogEntry ED⟩, ⟨LogEntry EE⟩, ⟨LogEntry EF⟩, ⟨LogEntry EG⟩, ⟨LogEntry EH⟩, ⟨LogEntry EI⟩, ⟨LogEntry EJ⟩, ⟨LogEntry EK⟩, ⟨LogEntry EL⟩, ⟨LogEntry EM⟩, ⟨LogEntry EN⟩, ⟨LogEntry EO⟩, ⟨LogEntry EP⟩, ⟨LogEntry EQ⟩, ⟨LogEntry ER⟩, ⟨LogEntry ES⟩, ⟨LogEntry ET⟩, ⟨LogEntry EU⟩, ⟨LogEntry EV⟩, ⟨LogEntry EW⟩, ⟨LogEntry EX⟩, ⟨LogEntry EY⟩, ⟨LogEntry EZ⟩, ⟨LogEntry FA⟩, ⟨LogEntry FB⟩, ⟨LogEntry FC⟩, ⟨LogEntry FD⟩, ⟨LogEntry FE⟩, ⟨LogEntry FF⟩, ⟨LogEntry FG⟩, ⟨LogEntry FH⟩, ⟨LogEntry FI⟩, ⟨LogEntry FJ⟩, ⟨LogEntry FK⟩, ⟨LogEntry FL⟩, ⟨LogEntry FM⟩, ⟨LogEntry FN⟩, ⟨LogEntry FO⟩, ⟨LogEntry FP⟩, ⟨LogEntry FQ⟩, ⟨LogEntry FR⟩, ⟨LogEntry FS⟩, ⟨LogEntry FT⟩, ⟨LogEntry FU⟩, ⟨LogEntry FV⟩, ⟨LogEntry FW⟩, ⟨LogEntry FX⟩, ⟨LogEntry FY⟩, ⟨LogEntry FZ⟩, ⟨LogEntry GA⟩, ⟨LogEntry GB⟩, ⟨LogEntry GC⟩, ⟨LogEntry GD⟩, ⟨LogEntry GE⟩, ⟨LogEntry GF⟩, ⟨LogEntry GG⟩, ⟨LogEntry GH⟩, ⟨LogEntry GI⟩, ⟨LogEntry GJ⟩, ⟨LogEntry GK⟩, ⟨LogEntry GL⟩, ⟨LogEntry GM⟩, ⟨LogEntry GN⟩, ⟨LogEntry GO⟩, ⟨LogEntry GP⟩, ⟨LogEntry GQ⟩, ⟨LogEntry GR⟩, ⟨LogEntry GS⟩, ⟨LogEntry GT⟩, ⟨LogEntry GU⟩, ⟨LogEntry GV⟩, ⟨LogEntry GW⟩, ⟨LogEntry GX⟩, ⟨LogEntry DL⟩, ⟨LogEntry DM⟩] = [LogEntry(i, "INFO", f"Message {i}") for i in range(100)]147print(f"✓ Good: Large collections ({len(logs[⟨LogEntry DC⟩, ⟨LogEntry DD⟩, ⟨LogEntry DE⟩, ⟨LogEntry DF⟩, ⟨LogEntry DG⟩, ⟨LogEntry DH⟩, ⟨LogEntry DI⟩, ⟨LogEntry DJ⟩, ⟨LogEntry DK⟩, ⟨LogEntry DN⟩, ⟨LogEntry DO⟩, ⟨LogEntry DP⟩, ⟨LogEntry DQ⟩, ⟨LogEntry DR⟩, ⟨LogEntry DS⟩, ⟨LogEntry DT⟩, ⟨LogEntry DU⟩, ⟨LogEntry DV⟩, ⟨LogEntry DW⟩, ⟨LogEntry DX⟩, ⟨LogEntry DY⟩, ⟨LogEntry DZ⟩, ⟨LogEntry EA⟩, ⟨LogEntry EB⟩, ⟨LogEntry EC⟩, ⟨LogEntry ED⟩, ⟨LogEntry EE⟩, ⟨LogEntry EF⟩, ⟨LogEntry EG⟩, ⟨LogEntry EH⟩, ⟨LogEntry EI⟩, ⟨LogEntry EJ⟩, ⟨LogEntry EK⟩, ⟨LogEntry EL⟩, ⟨LogEntry EM⟩, ⟨LogEntry EN⟩, ⟨LogEntry EO⟩, ⟨LogEntry EP⟩, ⟨LogEntry EQ⟩, ⟨LogEntry ER⟩, ⟨LogEntry ES⟩, ⟨LogEntry ET⟩, ⟨LogEntry EU⟩, ⟨LogEntry EV⟩, ⟨LogEntry EW⟩, ⟨LogEntry EX⟩, ⟨LogEntry EY⟩, ⟨LogEntry EZ⟩, ⟨LogEntry FA⟩, ⟨LogEntry FB⟩, ⟨LogEntry FC⟩, ⟨LogEntry FD⟩, ⟨LogEntry FE⟩, ⟨LogEntry FF⟩, ⟨LogEntry FG⟩, ⟨LogEntry FH⟩, ⟨LogEntry FI⟩, ⟨LogEntry FJ⟩, ⟨LogEntry FK⟩, ⟨LogEntry FL⟩, ⟨LogEntry FM⟩, ⟨LogEntry FN⟩, ⟨LogEntry FO⟩, ⟨LogEntry FP⟩, ⟨LogEntry FQ⟩, ⟨LogEntry FR⟩, ⟨LogEntry FS⟩, ⟨LogEntry FT⟩, ⟨LogEntry FU⟩, ⟨LogEntry FV⟩, ⟨LogEntry FW⟩, ⟨LogEntry FX⟩, ⟨LogEntry FY⟩, ⟨LogEntry FZ⟩, ⟨LogEntry GA⟩, ⟨LogEntry GB⟩, ⟨LogEntry GC⟩, ⟨LogEntry GD⟩, ⟨LogEntry GE⟩, ⟨LogEntry GF⟩, ⟨LogEntry GG⟩, ⟨LogEntry GH⟩, ⟨LogEntry GI⟩, ⟨LogEntry GJ⟩, ⟨LogEntry GK⟩, ⟨LogEntry GL⟩, ⟨LogEntry GM⟩, ⟨LogEntry GN⟩, ⟨LogEntry GO⟩, ⟨LogEntry GP⟩, ⟨LogEntry GQ⟩, ⟨LogEntry GR⟩, ⟨LogEntry GS⟩, ⟨LogEntry GT⟩, ⟨LogEntry GU⟩, ⟨LogEntry GV⟩, ⟨LogEntry GW⟩, ⟨LogEntry GX⟩, ⟨LogEntry DL⟩, ⟨LogEntry DM⟩])} entries)")148149# Embedded systems150print("\nEmbedded systems:")151152class SensorReading:153    __slots__ = ['sensor_id', 'value', 'unit']154    155    def __init__(self, sensor_id, value, unit):156        self.sensor_id = sensor_id157        self.value = value158        self.unit = unit159160reading = SensorReading(1, 23.5, "C")161print(f"✓ Good: Memory-constrained environments")
    output✓ Good: Large collections (100 entries)
    
    Embedded systems:
  24. self.sensor_id ← 1, self.value ← 23.5, self.unit ← C

    155def __init__(self⟨SensorReading GY⟩, sensor_id1, value23.5, unitC):156    self.sensor_id→ 1 = sensor_id1157    self.value→ 23.5 = value23.5158    self.unit→ C = unitC
  25. reading ← ⟨SensorReading GY⟩

    160reading→ ⟨SensorReading GY⟩ = SensorReading(1, 23.5, "C")161print(f"✓ Good: Memory-constrained environments")162163# Game development164print("\nGame development:")165166class Entity:167    __slots__ = ['id', 'x', 'y', 'sprite', 'health']168    169    def __init__(self, id, x, y, sprite, health):170        self.id = id171        self.x = x172        self.y = y173        self.sprite = sprite174        self.health = health175176# Good for thousands of game entities177entities = [Entity(i, i*10, i*20, f"sprite{i}", 100) for i in range(100)]178print(f"✓ Good: Game with {len(entities)} entities")
    output✓ Good: Memory-constrained environments
    
    Game development:
  26. self.id ← 0, self.x ← 0, self.y ← 0, self.sprite ← sprite0, self.health ← 100

    pass 1 of 100
    169def __init__(self⟨Entity GZ⟩, id0, x0, y0, spritesprite0, health100):170    self.id→ 0 = id0171    self.x→ 0 = x0172    self.y→ 0 = y0173    self.sprite→ sprite0 = spritesprite0174    self.health→ 100 = health100
    100 passes — pass 1 is the card above
    passselfidxyspriteself.idself.xself.yself.spriteself.health
    1⟨Entity GZ⟩000sprite0000sprite0100
    2⟨Entity HA⟩11020sprite111020sprite1100
    3⟨Entity HB⟩22040sprite222040sprite2100
    4⟨Entity HC⟩33060sprite333060sprite3100
    5⟨Entity HD⟩44080sprite444080sprite4100
    6⟨Entity HE⟩550100sprite5550100sprite5100
    7⟨Entity HF⟩660120sprite6660120sprite6100
    8⟨Entity HG⟩770140sprite7770140sprite7100
    9⟨Entity HH⟩880160sprite8880160sprite8100
    ⋯ 89 more passes ⋯
    99⟨Entity HI⟩989801960sprite98989801960sprite98100
    100⟨Entity HJ⟩999901980sprite99999901980sprite99100
  27. entities ← [⟨Entity GZ⟩, ⟨Entity HA⟩, ⟨Entity HB⟩, ⟨Entity HC⟩, ⟨Entity HD⟩, ⟨Entity HE⟩, ⟨Entity HF⟩, ⟨Entity HG⟩, ⟨Entity HH⟩, ⟨Entity HK⟩, ⟨Entity HL⟩, ⟨Entity HM⟩, ⟨Entity HN⟩, ⟨Entity HO⟩, ⟨Entity HP⟩, ⟨Entity HQ⟩, ⟨Entity HR⟩, ⟨Entity HS⟩, ⟨Entity HT⟩, ⟨Entity HU⟩, ⟨Entity HV⟩, ⟨Entity HW⟩, ⟨Entity HX⟩, ⟨Entity HY⟩, ⟨Entity HZ⟩, ⟨Entity IA⟩, ⟨Entity IB⟩, ⟨Entity IC⟩, ⟨Entity ID⟩, ⟨Entity IE⟩, ⟨Entity IF⟩, ⟨Entity IG⟩, ⟨Entity IH⟩, ⟨Entity II⟩, ⟨Entity IJ⟩, ⟨Entity IK⟩, ⟨Entity IL⟩, ⟨Entity IM⟩, ⟨Entity IN⟩, ⟨Entity IO⟩, ⟨Entity IP⟩, ⟨Entity IQ⟩, ⟨Entity IR⟩, ⟨Entity IS⟩, ⟨Entity IT⟩, ⟨Entity IU⟩, ⟨Entity IV⟩, ⟨Entity IW⟩, ⟨Entity IX⟩, ⟨Entity IY⟩, ⟨Entity IZ⟩, ⟨Entity JA⟩, ⟨Entity JB⟩, ⟨Entity JC⟩, ⟨Entity JD⟩, ⟨Entity JE⟩, ⟨Entity JF⟩, ⟨Entity JG⟩, ⟨Entity JH⟩, ⟨Entity JI⟩, ⟨Entity JJ⟩, ⟨Entity JK⟩, ⟨Entity JL⟩, ⟨Entity JM⟩, ⟨Entity JN⟩, ⟨Entity JO⟩, ⟨Entity JP⟩, ⟨Entity JQ⟩, ⟨Entity JR⟩, ⟨Entity JS⟩, ⟨Entity JT⟩, ⟨Entity JU⟩, ⟨Entity JV⟩, ⟨Entity JW⟩, ⟨Entity JX⟩, ⟨Entity JY⟩, ⟨Entity JZ⟩, ⟨Entity KA⟩, ⟨Entity KB⟩, ⟨Entity KC⟩, ⟨Entity KD⟩, ⟨Entity KE⟩, ⟨Entity KF⟩, ⟨Entity KG⟩, ⟨Entity KH⟩, ⟨Entity KI⟩, ⟨Entity KJ⟩, ⟨Entity KK⟩, ⟨Entity KL⟩, ⟨Entity KM⟩, ⟨Entity KN⟩, ⟨Entity KO⟩, ⟨Entity KP⟩, ⟨Entity KQ⟩, ⟨Entity KR⟩, ⟨Entity KS⟩, ⟨Entity KT⟩, ⟨Entity KU⟩, ⟨Entity HI⟩, ⟨Entity HJ⟩]

    176# Good for thousands of game entities177entities→ [⟨Entity GZ⟩, ⟨Entity HA⟩, ⟨Entity HB⟩, ⟨Entity HC⟩, ⟨Entity HD⟩, ⟨Entity HE⟩, ⟨Entity HF⟩, ⟨Entity HG⟩, ⟨Entity HH⟩, ⟨Entity HK⟩, ⟨Entity HL⟩, ⟨Entity HM⟩, ⟨Entity HN⟩, ⟨Entity HO⟩, ⟨Entity HP⟩, ⟨Entity HQ⟩, ⟨Entity HR⟩, ⟨Entity HS⟩, ⟨Entity HT⟩, ⟨Entity HU⟩, ⟨Entity HV⟩, ⟨Entity HW⟩, ⟨Entity HX⟩, ⟨Entity HY⟩, ⟨Entity HZ⟩, ⟨Entity IA⟩, ⟨Entity IB⟩, ⟨Entity IC⟩, ⟨Entity ID⟩, ⟨Entity IE⟩, ⟨Entity IF⟩, ⟨Entity IG⟩, ⟨Entity IH⟩, ⟨Entity II⟩, ⟨Entity IJ⟩, ⟨Entity IK⟩, ⟨Entity IL⟩, ⟨Entity IM⟩, ⟨Entity IN⟩, ⟨Entity IO⟩, ⟨Entity IP⟩, ⟨Entity IQ⟩, ⟨Entity IR⟩, ⟨Entity IS⟩, ⟨Entity IT⟩, ⟨Entity IU⟩, ⟨Entity IV⟩, ⟨Entity IW⟩, ⟨Entity IX⟩, ⟨Entity IY⟩, ⟨Entity IZ⟩, ⟨Entity JA⟩, ⟨Entity JB⟩, ⟨Entity JC⟩, ⟨Entity JD⟩, ⟨Entity JE⟩, ⟨Entity JF⟩, ⟨Entity JG⟩, ⟨Entity JH⟩, ⟨Entity JI⟩, ⟨Entity JJ⟩, ⟨Entity JK⟩, ⟨Entity JL⟩, ⟨Entity JM⟩, ⟨Entity JN⟩, ⟨Entity JO⟩, ⟨Entity JP⟩, ⟨Entity JQ⟩, ⟨Entity JR⟩, ⟨Entity JS⟩, ⟨Entity JT⟩, ⟨Entity JU⟩, ⟨Entity JV⟩, ⟨Entity JW⟩, ⟨Entity JX⟩, ⟨Entity JY⟩, ⟨Entity JZ⟩, ⟨Entity KA⟩, ⟨Entity KB⟩, ⟨Entity KC⟩, ⟨Entity KD⟩, ⟨Entity KE⟩, ⟨Entity KF⟩, ⟨Entity KG⟩, ⟨Entity KH⟩, ⟨Entity KI⟩, ⟨Entity KJ⟩, ⟨Entity KK⟩, ⟨Entity KL⟩, ⟨Entity KM⟩, ⟨Entity KN⟩, ⟨Entity KO⟩, ⟨Entity KP⟩, ⟨Entity KQ⟩, ⟨Entity KR⟩, ⟨Entity KS⟩, ⟨Entity KT⟩, ⟨Entity KU⟩, ⟨Entity HI⟩, ⟨Entity HJ⟩] = [Entity(i, i*10, i*20, f"sprite{i}", 100) for i in range(100)]178print(f"✓ Good: Game with {len(entities[⟨Entity GZ⟩, ⟨Entity HA⟩, ⟨Entity HB⟩, ⟨Entity HC⟩, ⟨Entity HD⟩, ⟨Entity HE⟩, ⟨Entity HF⟩, ⟨Entity HG⟩, ⟨Entity HH⟩, ⟨Entity HK⟩, ⟨Entity HL⟩, ⟨Entity HM⟩, ⟨Entity HN⟩, ⟨Entity HO⟩, ⟨Entity HP⟩, ⟨Entity HQ⟩, ⟨Entity HR⟩, ⟨Entity HS⟩, ⟨Entity HT⟩, ⟨Entity HU⟩, ⟨Entity HV⟩, ⟨Entity HW⟩, ⟨Entity HX⟩, ⟨Entity HY⟩, ⟨Entity HZ⟩, ⟨Entity IA⟩, ⟨Entity IB⟩, ⟨Entity IC⟩, ⟨Entity ID⟩, ⟨Entity IE⟩, ⟨Entity IF⟩, ⟨Entity IG⟩, ⟨Entity IH⟩, ⟨Entity II⟩, ⟨Entity IJ⟩, ⟨Entity IK⟩, ⟨Entity IL⟩, ⟨Entity IM⟩, ⟨Entity IN⟩, ⟨Entity IO⟩, ⟨Entity IP⟩, ⟨Entity IQ⟩, ⟨Entity IR⟩, ⟨Entity IS⟩, ⟨Entity IT⟩, ⟨Entity IU⟩, ⟨Entity IV⟩, ⟨Entity IW⟩, ⟨Entity IX⟩, ⟨Entity IY⟩, ⟨Entity IZ⟩, ⟨Entity JA⟩, ⟨Entity JB⟩, ⟨Entity JC⟩, ⟨Entity JD⟩, ⟨Entity JE⟩, ⟨Entity JF⟩, ⟨Entity JG⟩, ⟨Entity JH⟩, ⟨Entity JI⟩, ⟨Entity JJ⟩, ⟨Entity JK⟩, ⟨Entity JL⟩, ⟨Entity JM⟩, ⟨Entity JN⟩, ⟨Entity JO⟩, ⟨Entity JP⟩, ⟨Entity JQ⟩, ⟨Entity JR⟩, ⟨Entity JS⟩, ⟨Entity JT⟩, ⟨Entity JU⟩, ⟨Entity JV⟩, ⟨Entity JW⟩, ⟨Entity JX⟩, ⟨Entity JY⟩, ⟨Entity JZ⟩, ⟨Entity KA⟩, ⟨Entity KB⟩, ⟨Entity KC⟩, ⟨Entity KD⟩, ⟨Entity KE⟩, ⟨Entity KF⟩, ⟨Entity KG⟩, ⟨Entity KH⟩, ⟨Entity KI⟩, ⟨Entity KJ⟩, ⟨Entity KK⟩, ⟨Entity KL⟩, ⟨Entity KM⟩, ⟨Entity KN⟩, ⟨Entity KO⟩, ⟨Entity KP⟩, ⟨Entity KQ⟩, ⟨Entity KR⟩, ⟨Entity KS⟩, ⟨Entity KT⟩, ⟨Entity KU⟩, ⟨Entity HI⟩, ⟨Entity HJ⟩])} entities")179180# Practical decision guide181print("\nPractical decision guide:")182183print("\nUse __slots__ when:")184print("  ✓ Creating many instances (>1000)")185print("  ✓ Attributes are fixed and known")186print("  ✓ Memory is constrained")187print("  ✓ Attribute access speed matters")188print("  ✓ Preventing attribute typos is valuable")189190print("\nAvoid __slots__ when:")191print("  ✗ Dynamic attributes are needed")192print("  ✗ Only a few instances exist")193print("  ✗ Complex inheritance hierarchies")194print("  ✗ Need __dict__ for introspection")195print("  ✗ Using libraries that expect __dict__")196197# Real-world example198print("\nReal-world example:")199200# Time series data storage201class TimeSeriesPoint:202    __slots__ = ['timestamp', 'value']203    204    def __init__(self, timestamp, value):205        self.timestamp = timestamp206        self.value = value207208# Simulate 1 day of per-second data209seconds_per_day→ 86400 = 86400210timeseries = [TimeSeriesPoint(i, i * 0.1) for i in range(100)]  # Sample
    output✓ Good: Game with 100 entities
    
    Practical decision guide:
    
    Use __slots__ when:
      ✓ Creating many instances (>1000)
      ✓ Attributes are fixed and known
      ✓ Memory is constrained
      ✓ Attribute access speed matters
      ✓ Preventing attribute typos is valuable
    
    Avoid __slots__ when:
      ✗ Dynamic attributes are needed
      ✗ Only a few instances exist
      ✗ Complex inheritance hierarchies
      ✗ Need __dict__ for introspection
      ✗ Using libraries that expect __dict__
    
    Real-world example:
  28. self.timestamp ← 0, self.value ← 0.0

    pass 1 of 100
    204def __init__(self⟨TimeSeriesPoint KV⟩, timestamp0, value0.0):205    self.timestamp→ 0 = timestamp0206    self.value→ 0.0 = value0.0
    100 passes — pass 1 is the card above
    passselftimestampvalueself.timestampself.value
    1⟨TimeSeriesPoint KV⟩00.000.0
    2⟨TimeSeriesPoint KW⟩10.110.1
    3⟨TimeSeriesPoint KX⟩20.220.2
    4⟨TimeSeriesPoint KY⟩30.3000000000000000430.30000000000000004
    5⟨TimeSeriesPoint KZ⟩40.440.4
    6⟨TimeSeriesPoint LA⟩50.550.5
    7⟨TimeSeriesPoint LB⟩60.600000000000000160.6000000000000001
    8⟨TimeSeriesPoint LC⟩70.700000000000000170.7000000000000001
    9⟨TimeSeriesPoint LD⟩80.880.8
    ⋯ 89 more passes ⋯
    99⟨TimeSeriesPoint LE⟩989.8989.8
    100⟨TimeSeriesPoint LF⟩999.9999.9
  29. timeseries ← [⟨TimeSeriesPoint KV⟩, ⟨TimeSeriesPoint KW⟩, ⟨TimeSeriesPoint KX⟩, ⟨TimeSeriesPoint KY⟩, ⟨TimeSeriesPoint KZ⟩, ⟨TimeSeriesPoint LA⟩, ⟨TimeSeriesPoint LB⟩, ⟨TimeSeriesPoint LC⟩, ⟨TimeSeriesPoint LD⟩, ⟨TimeSeriesPoint LG⟩, ⟨TimeSeriesPoint LH⟩, ⟨TimeSeriesPoint LI⟩, ⟨TimeSeriesPoint LJ⟩, ⟨TimeSeriesPoint LK⟩, ⟨TimeSeriesPoint LL⟩, ⟨TimeSeriesPoint LM⟩, ⟨TimeSeriesPoint LN⟩, ⟨TimeSeriesPoint LO⟩, ⟨TimeSeriesPoint LP⟩, ⟨TimeSeriesPoint LQ⟩, ⟨TimeSeriesPoint LR⟩, ⟨TimeSeriesPoint LS⟩, ⟨TimeSeriesPoint LT⟩, ⟨TimeSeriesPoint LU⟩, ⟨TimeSeriesPoint LV⟩, ⟨TimeSeriesPoint LW⟩, ⟨TimeSeriesPoint LX⟩, ⟨TimeSeriesPoint LY⟩, ⟨TimeSeriesPoint LZ⟩, ⟨TimeSeriesPoint MA⟩, ⟨TimeSeriesPoint MB⟩, ⟨TimeSeriesPoint MC⟩, ⟨TimeSeriesPoint MD⟩, ⟨TimeSeriesPoint ME⟩, ⟨TimeSeriesPoint MF⟩, ⟨TimeSeriesPoint MG⟩, ⟨TimeSeriesPoint MH⟩, ⟨TimeSeriesPoint MI⟩, ⟨TimeSeriesPoint MJ⟩, ⟨TimeSeriesPoint MK⟩, ⟨TimeSeriesPoint ML⟩, ⟨TimeSeriesPoint MM⟩, ⟨TimeSeriesPoint MN⟩, ⟨TimeSeriesPoint MO⟩, ⟨TimeSeriesPoint MP⟩, ⟨TimeSeriesPoint MQ⟩, ⟨TimeSeriesPoint MR⟩, ⟨TimeSeriesPoint MS⟩, ⟨TimeSeriesPoint MT⟩, ⟨TimeSeriesPoint MU⟩, ⟨TimeSeriesPoint MV⟩, ⟨TimeSeriesPoint MW⟩, ⟨TimeSeriesPoint MX⟩, ⟨TimeSeriesPoint MY⟩, ⟨TimeSeriesPoint MZ⟩, ⟨TimeSeriesPoint NA⟩, ⟨TimeSeriesPoint NB⟩, ⟨TimeSeriesPoint NC⟩, ⟨TimeSeriesPoint ND⟩, ⟨TimeSeriesPoint NE⟩, ⟨TimeSeriesPoint NF⟩, ⟨TimeSeriesPoint NG⟩, ⟨TimeSeriesPoint NH⟩, ⟨TimeSeriesPoint NI⟩, ⟨TimeSeriesPoint NJ⟩, ⟨TimeSeriesPoint NK⟩, ⟨TimeSeriesPoint NL⟩, ⟨TimeSeriesPoint NM⟩, ⟨TimeSeriesPoint NN⟩, ⟨TimeSeriesPoint NO⟩, ⟨TimeSeriesPoint NP⟩, ⟨TimeSeriesPoint NQ⟩, ⟨TimeSeriesPoint NR⟩, ⟨TimeSeriesPoint NS⟩, ⟨TimeSeriesPoint NT⟩, ⟨TimeSeriesPoint NU⟩, ⟨TimeSeriesPoint NV⟩, ⟨TimeSeriesPoint NW⟩, ⟨TimeSeriesPoint NX⟩, ⟨TimeSeriesPoint NY⟩, ⟨TimeSeriesPoint NZ⟩, ⟨TimeSeriesPoint OA⟩, ⟨TimeSeriesPoint OB⟩, ⟨TimeSeriesPoint OC⟩, ⟨TimeSeriesPoint OD⟩, ⟨TimeSeriesPoint OE⟩, ⟨TimeSeriesPoint OF⟩, ⟨TimeSeriesPoint OG⟩, ⟨TimeSeriesPoint OH⟩, ⟨TimeSeriesPoint OI⟩, ⟨TimeSeriesPoint OJ⟩, ⟨TimeSeriesPoint OK⟩, ⟨TimeSeriesPoint OL⟩, ⟨TimeSeriesPoint OM⟩, ⟨TimeSeriesPoint ON⟩, ⟨TimeSeriesPoint OO⟩, ⟨TimeSeriesPoint OP⟩, ⟨TimeSeriesPoint OQ⟩, ⟨TimeSeriesPoint LE⟩, ⟨TimeSeriesPoint LF⟩]

    209seconds_per_day = 86400210timeseries→ [⟨TimeSeriesPoint KV⟩, ⟨TimeSeriesPoint KW⟩, ⟨TimeSeriesPoint KX⟩, ⟨TimeSeriesPoint KY⟩, ⟨TimeSeriesPoint KZ⟩, ⟨TimeSeriesPoint LA⟩, ⟨TimeSeriesPoint LB⟩, ⟨TimeSeriesPoint LC⟩, ⟨TimeSeriesPoint LD⟩, ⟨TimeSeriesPoint LG⟩, ⟨TimeSeriesPoint LH⟩, ⟨TimeSeriesPoint LI⟩, ⟨TimeSeriesPoint LJ⟩, ⟨TimeSeriesPoint LK⟩, ⟨TimeSeriesPoint LL⟩, ⟨TimeSeriesPoint LM⟩, ⟨TimeSeriesPoint LN⟩, ⟨TimeSeriesPoint LO⟩, ⟨TimeSeriesPoint LP⟩, ⟨TimeSeriesPoint LQ⟩, ⟨TimeSeriesPoint LR⟩, ⟨TimeSeriesPoint LS⟩, ⟨TimeSeriesPoint LT⟩, ⟨TimeSeriesPoint LU⟩, ⟨TimeSeriesPoint LV⟩, ⟨TimeSeriesPoint LW⟩, ⟨TimeSeriesPoint LX⟩, ⟨TimeSeriesPoint LY⟩, ⟨TimeSeriesPoint LZ⟩, ⟨TimeSeriesPoint MA⟩, ⟨TimeSeriesPoint MB⟩, ⟨TimeSeriesPoint MC⟩, ⟨TimeSeriesPoint MD⟩, ⟨TimeSeriesPoint ME⟩, ⟨TimeSeriesPoint MF⟩, ⟨TimeSeriesPoint MG⟩, ⟨TimeSeriesPoint MH⟩, ⟨TimeSeriesPoint MI⟩, ⟨TimeSeriesPoint MJ⟩, ⟨TimeSeriesPoint MK⟩, ⟨TimeSeriesPoint ML⟩, ⟨TimeSeriesPoint MM⟩, ⟨TimeSeriesPoint MN⟩, ⟨TimeSeriesPoint MO⟩, ⟨TimeSeriesPoint MP⟩, ⟨TimeSeriesPoint MQ⟩, ⟨TimeSeriesPoint MR⟩, ⟨TimeSeriesPoint MS⟩, ⟨TimeSeriesPoint MT⟩, ⟨TimeSeriesPoint MU⟩, ⟨TimeSeriesPoint MV⟩, ⟨TimeSeriesPoint MW⟩, ⟨TimeSeriesPoint MX⟩, ⟨TimeSeriesPoint MY⟩, ⟨TimeSeriesPoint MZ⟩, ⟨TimeSeriesPoint NA⟩, ⟨TimeSeriesPoint NB⟩, ⟨TimeSeriesPoint NC⟩, ⟨TimeSeriesPoint ND⟩, ⟨TimeSeriesPoint NE⟩, ⟨TimeSeriesPoint NF⟩, ⟨TimeSeriesPoint NG⟩, ⟨TimeSeriesPoint NH⟩, ⟨TimeSeriesPoint NI⟩, ⟨TimeSeriesPoint NJ⟩, ⟨TimeSeriesPoint NK⟩, ⟨TimeSeriesPoint NL⟩, ⟨TimeSeriesPoint NM⟩, ⟨TimeSeriesPoint NN⟩, ⟨TimeSeriesPoint NO⟩, ⟨TimeSeriesPoint NP⟩, ⟨TimeSeriesPoint NQ⟩, ⟨TimeSeriesPoint NR⟩, ⟨TimeSeriesPoint NS⟩, ⟨TimeSeriesPoint NT⟩, ⟨TimeSeriesPoint NU⟩, ⟨TimeSeriesPoint NV⟩, ⟨TimeSeriesPoint NW⟩, ⟨TimeSeriesPoint NX⟩, ⟨TimeSeriesPoint NY⟩, ⟨TimeSeriesPoint NZ⟩, ⟨TimeSeriesPoint OA⟩, ⟨TimeSeriesPoint OB⟩, ⟨TimeSeriesPoint OC⟩, ⟨TimeSeriesPoint OD⟩, ⟨TimeSeriesPoint OE⟩, ⟨TimeSeriesPoint OF⟩, ⟨TimeSeriesPoint OG⟩, ⟨TimeSeriesPoint OH⟩, ⟨TimeSeriesPoint OI⟩, ⟨TimeSeriesPoint OJ⟩, ⟨TimeSeriesPoint OK⟩, ⟨TimeSeriesPoint OL⟩, ⟨TimeSeriesPoint OM⟩, ⟨TimeSeriesPoint ON⟩, ⟨TimeSeriesPoint OO⟩, ⟨TimeSeriesPoint OP⟩, ⟨TimeSeriesPoint OQ⟩, ⟨TimeSeriesPoint LE⟩, ⟨TimeSeriesPoint LF⟩] = [TimeSeriesPoint(i, i * 0.1) for i in range(100)]  # Sample211212print(f"✓ Excellent use case: Time series with {len(timeseries[⟨TimeSeriesPoint KV⟩, ⟨TimeSeriesPoint KW⟩, ⟨TimeSeriesPoint KX⟩, ⟨TimeSeriesPoint KY⟩, ⟨TimeSeriesPoint KZ⟩, ⟨TimeSeriesPoint LA⟩, ⟨TimeSeriesPoint LB⟩, ⟨TimeSeriesPoint LC⟩, ⟨TimeSeriesPoint LD⟩, ⟨TimeSeriesPoint LG⟩, ⟨TimeSeriesPoint LH⟩, ⟨TimeSeriesPoint LI⟩, ⟨TimeSeriesPoint LJ⟩, ⟨TimeSeriesPoint LK⟩, ⟨TimeSeriesPoint LL⟩, ⟨TimeSeriesPoint LM⟩, ⟨TimeSeriesPoint LN⟩, ⟨TimeSeriesPoint LO⟩, ⟨TimeSeriesPoint LP⟩, ⟨TimeSeriesPoint LQ⟩, ⟨TimeSeriesPoint LR⟩, ⟨TimeSeriesPoint LS⟩, ⟨TimeSeriesPoint LT⟩, ⟨TimeSeriesPoint LU⟩, ⟨TimeSeriesPoint LV⟩, ⟨TimeSeriesPoint LW⟩, ⟨TimeSeriesPoint LX⟩, ⟨TimeSeriesPoint LY⟩, ⟨TimeSeriesPoint LZ⟩, ⟨TimeSeriesPoint MA⟩, ⟨TimeSeriesPoint MB⟩, ⟨TimeSeriesPoint MC⟩, ⟨TimeSeriesPoint MD⟩, ⟨TimeSeriesPoint ME⟩, ⟨TimeSeriesPoint MF⟩, ⟨TimeSeriesPoint MG⟩, ⟨TimeSeriesPoint MH⟩, ⟨TimeSeriesPoint MI⟩, ⟨TimeSeriesPoint MJ⟩, ⟨TimeSeriesPoint MK⟩, ⟨TimeSeriesPoint ML⟩, ⟨TimeSeriesPoint MM⟩, ⟨TimeSeriesPoint MN⟩, ⟨TimeSeriesPoint MO⟩, ⟨TimeSeriesPoint MP⟩, ⟨TimeSeriesPoint MQ⟩, ⟨TimeSeriesPoint MR⟩, ⟨TimeSeriesPoint MS⟩, ⟨TimeSeriesPoint MT⟩, ⟨TimeSeriesPoint MU⟩, ⟨TimeSeriesPoint MV⟩, ⟨TimeSeriesPoint MW⟩, ⟨TimeSeriesPoint MX⟩, ⟨TimeSeriesPoint MY⟩, ⟨TimeSeriesPoint MZ⟩, ⟨TimeSeriesPoint NA⟩, ⟨TimeSeriesPoint NB⟩, ⟨TimeSeriesPoint NC⟩, ⟨TimeSeriesPoint ND⟩, ⟨TimeSeriesPoint NE⟩, ⟨TimeSeriesPoint NF⟩, ⟨TimeSeriesPoint NG⟩, ⟨TimeSeriesPoint NH⟩, ⟨TimeSeriesPoint NI⟩, ⟨TimeSeriesPoint NJ⟩, ⟨TimeSeriesPoint NK⟩, ⟨TimeSeriesPoint NL⟩, ⟨TimeSeriesPoint NM⟩, ⟨TimeSeriesPoint NN⟩, ⟨TimeSeriesPoint NO⟩, ⟨TimeSeriesPoint NP⟩, ⟨TimeSeriesPoint NQ⟩, ⟨TimeSeriesPoint NR⟩, ⟨TimeSeriesPoint NS⟩, ⟨TimeSeriesPoint NT⟩, ⟨TimeSeriesPoint NU⟩, ⟨TimeSeriesPoint NV⟩, ⟨TimeSeriesPoint NW⟩, ⟨TimeSeriesPoint NX⟩, ⟨TimeSeriesPoint NY⟩, ⟨TimeSeriesPoint NZ⟩, ⟨TimeSeriesPoint OA⟩, ⟨TimeSeriesPoint OB⟩, ⟨TimeSeriesPoint OC⟩, ⟨TimeSeriesPoint OD⟩, ⟨TimeSeriesPoint OE⟩, ⟨TimeSeriesPoint OF⟩, ⟨TimeSeriesPoint OG⟩, ⟨TimeSeriesPoint OH⟩, ⟨TimeSeriesPoint OI⟩, ⟨TimeSeriesPoint OJ⟩, ⟨TimeSeriesPoint OK⟩, ⟨TimeSeriesPoint OL⟩, ⟨TimeSeriesPoint OM⟩, ⟨TimeSeriesPoint ON⟩, ⟨TimeSeriesPoint OO⟩, ⟨TimeSeriesPoint OP⟩, ⟨TimeSeriesPoint OQ⟩, ⟨TimeSeriesPoint LE⟩, ⟨TimeSeriesPoint LF⟩])} data points")213print(f"  Each point: timestamp + value")214print(f"  Fixed schema, many instances, memory-efficient")
    output✓ Excellent use case: Time series with 100 data points
      Each point: timestamp + value
      Fixed schema, many instances, memory-efficient

The decision comes down to: Do you have many instances? Are attributes fixed and known? Is memory or access speed a concern?

slots decision Use `__slots__` when creating many instances of simple classes; avoid it when you need dynamic attributes or have complex inheritance.

Benefits

  • Memory savings: ~40-50% reduction for simple classes
  • Faster attribute access: No dict lookup overhead
  • Type safety: Prevents typos in attribute names

Limitations

  • No dynamic attributes after instantiation
  • Inheritance requires care (all classes need __slots__)
  • No __dict__ by default (breaks some libraries)
  • Cannot use with multiple inheritance from slotted classes with non-empty slots

Exercise: slots_practice.py

Create a Point class with __slots__ and compare its memory usage to a regular class