Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте __slots__ as Descriptors | Descriptors in the Wild
Python Descriptors Explained

__slots__ as Descriptors

Свайпніть щоб показати меню

In the memory course, __slots__ was introduced as a way to eliminate __dict__ and reduce per-instance memory. The mechanism that makes __slots__ work is the descriptor protocol – each slot is implemented as a data descriptor called a member descriptor, automatically created by the metaclass when the class is defined.

What Python Creates for Each Slot

When you define __slots__, Python creates a member_descriptor object for each listed attribute and stores it as a class attribute. These are data descriptors – they define __get__, __set__, and __delete__:

12345678910111213141516
# Inspecting the descriptors created by __slots__ class Position: __slots__ = ("position_id", "ticker", "price") def __init__(self, position_id, ticker, price): self.position_id = position_id self.ticker = ticker self.price = price # Each slot becomes a member_descriptor on the class print(type(Position.__dict__["position_id"])) # <class 'member_descriptor'> print(type(Position.__dict__["ticker"])) # <class 'member_descriptor'> print(hasattr(Position.__dict__["price"], "__get__")) # True print(hasattr(Position.__dict__["price"], "__set__")) # True print(hasattr(Position.__dict__["price"], "__delete__")) # True

How Slot Descriptors Store Values

Unlike a custom descriptor that stores values in obj.__dict__, member descriptors store values in a fixed-size C array on the instance. This is why slots are more memory-efficient – no dict overhead, just a compact array of pointers:

1234567891011121314151617181920212223242526
import sys # Comparing memory between __dict__ and __slots__ instances class WithDict: def __init__(self, position_id, ticker, price): self.position_id = position_id self.ticker = ticker self.price = price class WithSlots: __slots__ = ("position_id", "ticker", "price") def __init__(self, position_id, ticker, price): self.position_id = position_id self.ticker = ticker self.price = price with_dict = WithDict("P-001", "AAPL", 189.50) with_slots = WithSlots("P-001", "AAPL", 189.50) print(f"WithDict instance size: {sys.getsizeof(with_dict)} bytes") print(f"WithSlots instance size: {sys.getsizeof(with_slots)} bytes") # __dict__ exists on WithDict, not on WithSlots print(hasattr(with_dict, "__dict__")) # True print(hasattr(with_slots, "__dict__")) # False

Slot Descriptors Are Data Descriptors

Because slot descriptors define __set__, they have higher priority than instance __dict__ in the lookup chain. This is exactly why you cannot accidentally shadow a slot with an instance attribute:

1234567891011121314
# Slot descriptor takes priority – cannot be shadowed class Config: __slots__ = ("debug",) def __init__(self, debug): self.debug = debug config = Config(False) # Trying to set an attribute not in __slots__ raises AttributeError try: config.extra = "value" except AttributeError as error: print(error) # 'Config' object has no attribute 'extra'

Slots in Inheritance

Subclasses that do not define their own __slots__ get a __dict__ back, negating the memory savings:

123456789101112131415
# Inheritance and __slots__ class Base: __slots__ = ("base_id",) class ChildWithSlots(Base): __slots__ = ("child_value",) # Proper – extends slots class ChildWithoutSlots(Base): pass # Gets __dict__ – memory savings lost child_with = ChildWithSlots() child_without = ChildWithoutSlots() print(hasattr(child_with, "__dict__")) # False – slots only print(hasattr(child_without, "__dict__")) # True – __dict__ is back
question mark

Why can you not add an attribute to an instance whose class uses __slots__ if the attribute is not listed in __slots__?

Виберіть правильну відповідь

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 3

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Секція 2. Розділ 3
some-alt