ReviseAlgo Logo

Encapsulation

Descriptors

Advanced attribute access control via descriptor protocol

Interview: Advanced Python — tests understanding of descriptor protocol, __set_name__, and how properties/slots work under the hood

Last Updated: June 12, 2026 6 min read

Descriptors are objects that define how attribute access works via the descriptor protocol (__get__, __set__, __delete__). They're the mechanism behind @property, __slots__, class methods, and static methods. Descriptors enable reusable, composable attribute management across multiple classes.

Descriptor Protocol

  • __get__(self, obj, objtype=None): Called when attribute is accessed
  • __set__(self, obj, value): Called when attribute is assigned
  • __delete__(self, obj): Called when attribute is deleted
  • __set_name__(self, owner, name): Called when descriptor is assigned to a class attribute (Python 3.6+)

Data vs Non-Data Descriptors

  • Data descriptor: Defines both __get__ and __set__ — takes priority over instance __dict__
  • Non-data descriptor: Defines only __get__ — instance __dict__ takes priority
  • This distinction affects attribute lookup order: data descriptors > instance dict > non-data descriptors

Interview Tip

Know that @property, @classmethod, and @staticmethod are all implemented as descriptors. Understanding descriptors means understanding how Python's attribute access really works.

Use Cases

Reusable validation logic across many attributes and classes

Type enforcement for class fields (like Django model fields)

Lazy property loading (compute on first access, cache afterward)

ORM field definitions (SQLAlchemy columns are descriptors)

Implementing custom @property-like decorators for teams

Common Mistakes

Not implementing __set_name__ — descriptor doesn't know its attribute name

Storing value in descriptor instead of instance (shared across all instances!)

Not handling class-level access (obj is None in __get__)

Confusing data descriptors (with __set__) and non-data descriptors (without)

Using descriptors when @property would be simpler (overengineering for one-off cases)