A validating descriptor with __set_name__
A descriptor is an object stored on a class that controls what happens when an attribute is read, set or deleted, through __get__, __set__ and __set_name__. property, methods, classmethod, staticmethod and cached_property are all descriptors.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write an Upper descriptor class that stores any string assigned to it in upper case (use __set_name__ to learn the attribute name). Make a class User with two such attributes, name and city, set them to "ada" and "london", and print both.
Write two descriptor classes, one with __get__ and __set__ and one with only __get__. Put both on a class, write a string with the same name into the instance's __dict__ for each, and print what each attribute returns. Say which descriptor won and which lost.
Write a descriptor Counted whose __get__ counts how many times each instance read the attribute (keep the count in the instance's __dict__). Read it three times and print the instance's __dict__.
Explain it without notes
What is a descriptor, and what are the methods of the protocol?
What is the difference between a data descriptor and a non-data descriptor?
How does functools.cached_property work?
Why must a descriptor not store per-instance state on itself?
How does the descriptor protocol explain why self is passed automatically in obj.method(), and why Cls.method is a plain function?
Expected output
10 3 99
['_price', '_quantity']
Positive
ValueError: price must be positive, got -5
10