Разбор по шагам
1️⃣Декоратор @𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢 создаёт объект дескриптора, который хранит функцию 𝚗𝚊𝚖𝚎. Этот объект дескриптор помещается в словарь класса 𝚄𝚜𝚎𝚛.𝚍𝚒𝚌𝚝 под именем 𝚗𝚊𝚖𝚎.
2️⃣Выражение 𝚄𝚜𝚎𝚛.𝚗𝚊𝚖𝚎 — это обращение к атрибуту через класс (без создания экземпляра). Python находит дескриптор, но поскольку обращение идёт не через экземпляр, дескриптор просто возвращает сам себя — объект 𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢. Первый 𝚙𝚛𝚒𝚗𝚝 выводит что‑то вроде <𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢 𝚘𝚋𝚓𝚎𝚌𝚝 𝚊𝚝 𝟶𝚡...>.
3️⃣Выражение 𝚄𝚜𝚎𝚛() создаёт новый экземпляр класса 𝚄𝚜𝚎𝚛.
4️⃣Обращение .𝚗𝚊𝚖𝚎 на этом экземпляре заставляет дескриптор сработать: он вызывает сохранённую функцию 𝚗𝚊𝚖𝚎(𝚜𝚎𝚕𝚏) и возвращает её результат «𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎».
5️⃣Второй 𝚙𝚛𝚒𝚗𝚝 выводит строку «𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎».
Когда интерпретатор видит метод с декоратором 𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢, он примерно делает так:
🔘берёт функцию 𝚏𝚞𝚗𝚌 = 𝚄𝚜𝚎𝚛.𝚗𝚊𝚖𝚎;
🔘создаёт объект 𝚙𝚛𝚘𝚙 = 𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢(𝚏𝚞𝚗𝚌);
🔘кладёт его в класс: в 𝚄𝚜𝚎𝚛.𝚍𝚒𝚌𝚝 под ключом 𝚗𝚊𝚖𝚎 теперь лежит не функция, а объект 𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢.
Класс 𝚙𝚛𝚘𝚙𝚎𝚛𝚝𝚢 сам по себе — обычный класс, у которого реализованы методы 𝚐𝚎𝚝, 𝚜𝚎𝚝, 𝚍𝚎𝚕𝚎𝚝𝚎. Это и называют дескриптором.
Благодаря такому устройству
🔘можно писать 𝚞𝚜𝚎𝚛.𝚊𝚐𝚎 вместо 𝚞𝚜𝚎𝚛.𝚐𝚎𝚝_𝚊𝚐𝚎(), а под капотом при этом выполняется логика (валидация, преобразования, кэширование и т. п.);
🔘можно сперва сделать обычное поле 𝚞𝚜𝚎𝚛.𝚊𝚐𝚎, а позже заменить его на вычисляемое свойство, не ломая код, который его читает — внешний интерфейс (𝚞𝚜𝚎𝚛.𝚊𝚐𝚎) не меняется.
Post #4506
802
- 👍 5