Python
Summary - Descriptors
Combine __get__, __set__ and __set_name__ to write a Validated descriptor.
Recap: descriptors
In this group you learned the descriptor protocol. __get__ intercepts reads, __set__ writes, __delete__ deletes. A data descriptor implements both __get__ and __set__; a non-data descriptor only __get__.
You saw that @property is a data descriptor. With __set_name__ the descriptor learns its name. Now you will combine these into a Validated descriptor: store the name with __set_name__, return the value with __get__, reject negatives with __set__. This is a realistic validation layer.
Exercise Write a Validated descriptor
Write a Validated descriptor. In __set_name__(self, owner, name) set self.name = name and self.value = 0. __get__(self, obj, objtype=None) returns self.value. In __set__(self, obj, value) raise ValueError if the value is less than 0; otherwise set self.value = value. In a Product class define price = Validated(). Create an instance, set price = 100 and print it.
Show example solution
# Write the Validated descriptor
class Validated:
def __set_name__(self, owner, name):
self.name = name
self.value = 0
def __get__(self, obj, objtype=None):
return self.value
def __set__(self, obj, value):
if value < 0:
raise ValueError("negative")
self.value = value
class Product:
price = Validated()
p = Product()
p.price = 100
print(p.price)
What you learned
In this group you learned one of Python's most powerful features: the descriptor protocol. You intercepted attribute access with __get__, __set__ and __delete__. You saw the priority difference between data and non-data descriptors.
You learned that @property is a data descriptor behind the curtain. You added name awareness with __set_name__. In the summary you combined three methods into a Validated descriptor. This knowledge is key to understanding how Python frameworks work.
Test yourself
-
Which type of descriptor?
- a data descriptor only implements __get__
- property is non-data
- a non-data is overridden by the instance dict
- __set_name__ fires at instance level
Show answer
a non-data is overridden by the instance dict — answer: a non-data is overridden by the instance dict. Without __set__ it does not intercept writes.
-
Match all descriptor concepts
- __get__
- Reading
- __set__
- Writing
- __set_name__
- Name notification
- property
- Data descriptor
-
Final blank
class Validated:
def __set_name__(self, owner, name):
self.name = name
self.value = ____
def __get__(self, obj, objtype=None):
return self.value
Show answer
class Validated:
def __set_name__(self, owner, name):
self.name = name
self.value = 0
def __get__(self, obj, objtype=None):
return self.value
Next lesson: ast.parse