__slots__ vs __dict__
メニューを表示するにはスワイプしてください
Every Python object stores its instance attributes in a dictionary called __dict__. Dictionaries are flexible but carry significant memory overhead. For classes with a fixed set of attributes – especially when thousands of instances are created – __slots__ replaces __dict__ with a compact fixed-size structure.
The Default: __dict__
By default, every instance of a class gets its own __dict__ that can hold any attribute:
1234567891011121314import sys # Default class using __dict__ for attribute storage class Transaction: def __init__(self, transaction_id, amount, currency): self.transaction_id = transaction_id self.amount = amount self.currency = currency transaction = Transaction("TX001", 4500.0, "USD") print(transaction.__dict__) # {'transaction_id': 'TX001', 'amount': 4500.0, 'currency': 'USD'} print(sys.getsizeof(transaction)) # Object size – does not include __dict__ overhead print(sys.getsizeof(transaction.__dict__)) # Dict overhead – typically 184+ bytes
The dict overhead is constant per instance regardless of how many attributes are stored.
Using __slots__
Declaring __slots__ tells Python to allocate only the listed attributes – no __dict__ is created:
123456789101112131415import sys # Class using __slots__ for compact attribute storage class Transaction: __slots__ = ("transaction_id", "amount", "currency") def __init__(self, transaction_id, amount, currency): self.transaction_id = transaction_id self.amount = amount self.currency = currency transaction = Transaction("TX001", 4500.0, "USD") print(sys.getsizeof(transaction)) # Smaller – no __dict__ overhead print(hasattr(transaction, "__dict__")) # False
Measuring the Difference
The savings become significant when many instances are created:
12345678910111213141516171819202122232425262728293031323334import sys import tracemalloc # Comparing memory usage between __dict__ and __slots__ at scale class RecordWithDict: def __init__(self, record_id, value): self.record_id = record_id self.value = value class RecordWithSlots: __slots__ = ("record_id", "value") def __init__(self, record_id, value): self.record_id = record_id self.value = value tracemalloc.start() records_dict = [RecordWithDict(record_id, record_id * 1.5) for record_id in range(100000)] snapshot_dict = tracemalloc.take_snapshot() del records_dict tracemalloc.clear_traces() records_slots = [RecordWithSlots(record_id, record_id * 1.5) for record_id in range(100000)] snapshot_slots = tracemalloc.take_snapshot() dict_total = sum(s.size for s in snapshot_dict.statistics("lineno")) slots_total = sum(s.size for s in snapshot_slots.statistics("lineno")) print(f"With __dict__: {dict_total / 1024:.1f} KB") print(f"With __slots__: {slots_total / 1024:.1f} KB") tracemalloc.stop()
Limitations of __slots__
__slots__ comes with trade-offs:
- You cannot add attributes not listed in
__slots__at runtime; - Inheritance requires care — subclasses that don't define
__slots__get__dict__back; - Pickling and some dynamic patterns require additional work.
Use __slots__ when:
- The class has a fixed, known set of attributes;
- Many instances (thousands or more) will be created;
- Memory usage is a concern.
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください