CodeBlanks Logo Icon CodeBlanks

Non-data descriptor

Learn non-data descriptors with only __get__.

What is a non-data descriptor?

A non-data descriptor implements only __get__; there is no __set__. It intercepts reads but not writes.

This has an important consequence: a same-named entry in the instance dict (obj.__dict__) overrides a non-data descriptor. So writing box.label = "new" puts the value in the instance dict and subsequent reads return that value, not the descriptor. classmethod and staticmethod are non-data descriptors. This flexibility is ideal for simple computations that allow overriding.

Priority order

Python follows this priority for attribute access: first data descriptors, then the instance dict (obj.__dict__), then non-data descriptors, finally the class dict.

This explains why property (a data descriptor) overrides an instance value but classmethod (a non-data descriptor) can be overridden. A data descriptor always wins because it implements __set__ and writes go through it. A non-data descriptor only kicks in at read time and steps aside if the instance dict has a value.

Practice Computation with a non-data descriptor

Write a Squared non-data descriptor. Store self.base with __init__(self, base). __get__(self, obj, objtype=None) returns self.base ** 2. In a Math class define area = Squared(5). Create an instance and print area.

Starter code

main.py
# Write the Squared descriptor
# use it in the Math class
# print the result

Sample solution

main.py
# Write the Squared descriptor
class Squared:
    def __init__(self, base):
        self.base = base
    def __get__(self, obj, objtype=None):
        return self.base ** 2

class Math:
    area = Squared(5)

m = Math()
print(m.area)

Expected output

25

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Complete the non-data descriptor definition

Question
class Squared:
    def ______(self, obj, objtype=None):
        return self.base ** 2
Answer
class Squared:
    def __get(self, obj, objtype=None):
        return self.base ** 2

Explanation: A non-data descriptor implements only __get__.

2 Match non-data descriptor concepts

Term Meaning
__get__ Intercepts read
no __set__ Write is free
instance dict Overrides descriptor
classmethod Non-data example

3 When is a non-data descriptor overridden?

main.py
class Desc:
    def __get__(self, o, t=None):
        return "a"

class C:
    x = Desc()

c = C()
c.x = "b"
print(c.x)
  • Never overridden
  • When a value is written to the instance dict Correct answer
  • On class access
  • Only when __set__ is defined

Explanation: c.x = "b" goes to the instance dict; the non-data descriptor steps aside.

All lessons in Expert