Друкарня від WE.UA

Можливо, навіть далеко не всі чули, що таке дескриптори, але точно всі використовували їх
Я кажу це так впевнено, оскільки @property — є дескриптором 😮

Вступ

Оригінально, цей клас не задумувався як декоратор, а лише як явний транслятор між атрибутом та набором методів — геттер, сеттер та делеттер
Виглядати це має ось так:

# https://docs.python.org/uk/3/library/functions.html#property
class C:
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")

І “під капотом” у @property відбувається вся магія
Як зробити власний аналог — описано тут. Я ж хочу спробувати пояснити дескриптори простішим чином 😉

class CountDescriptor:
    def __init__(self, base_count=0):
        self.count = base_count

    def __get__(self, instance, owner):
        if instance is None:  # зчитуємо атрибут класу
            return self.count
        return self.count + instance.count


class Container:
    total = CountDescriptor(10)

    def __init__(self, count=15):
        self.count = count

print(Container.total)
print(Container().total)
print(Container(50).total)

Виглядає складно? 😨

Нічьо, зараз розберемось 😎

Клас CountDescriptor має метод __get__, отже є дескриптором
У цього класу також є атрибут count, що задається у конструкторі

Якщо атрибут (у нас — total) є дескриптором, то при спробі зчитати атрибут, Пайтон виконає у нього метод __get__, передавши першим аргументом об’єкт, а другим — клас цього об’єкту
Якщо ж зчитується атрибут класу, як перший атрибут буде передано None

У самому методі ми перевіримо це, і змінимо логіку:

  1. якщо зчитується атрибут класу, то результатом у методі буде власний атрибут count

  2. якщо зчитується атрибут об’єкту, то результатом буде власний атрибут count і доданий до нього атрибут count переданого об’єкту

Тепер перейдемо до класу Container
Цей клас має звичайний атрибут count, зі значенням за замовчуванням 10, у конструкторі
І головне, що має цей клас — атрибут-дескриптор: total

Отже:

  • для атрибуту total класу Container виконається умова 1,
    відповідно значення буде 10

  • для атрибуту total об’єкту Container() виконається умова 2,
    відповідно значення буде 25 (10 + 15)

  • для атрибуту total об’єкту Container(50) виконається умова 2,
    відповідно значення буде 60 (10 + 50)

Якщо все ж складно, можете погратись з цим кодом у моєму JupyterLite, або продебагати код і побачити як усі дії відбуваються наяву 🤔

Продебагати онлайн можна у Python Tutor

Усе те саме працює і для зміни значення атрибуту (__set__) та видалення атрибуту (__delete__). Якщо хоча б один з цих методів є у класі, його можна використовувати як дескриптор 🤓

Для чого ж можна використовувати дескриптори у реальному світі?)

Для всього 👀
Тобто, це всього лиш інструмент 😅
Він допомагає приховати складну реалізацію, при цьому залишивши дуже зручний інструмент у вигляді атрибуту

З поширених прикладів, це поля БД у ORM (зміна атрибута у об’єкті потім повпливає на зміни у БД), вищезгадані @property, а також його друзі @classmethod та @staticmethod, і навіть самі методи як такі 🤯
Це все прямим текстом пише в документації

За допомогою дескрипторів можна просто реалізувати кешування атрибутів, які можуть рідко використовуватись

А ще, якби це дивно не виглядало, методи дескриптора можуть бути асинхронними, і це відкриває ще більше можливостей, звісно зі своєю ложкою дьогтю у вигляді заплутаного використання 🥲

Післямови не буде, бо я такого не вмію 😢

Якщо вам подобається такий контент, підписуйтесь на мій телеграм-канал:
Python просто | з Коропом

Статті про вітчизняний бізнес та цікавих людей:

  • Вітаємо з Різдвом Христовим!

    Друкарня та платформа WE.UA вітають всіх наших читачів та авторів зі світлим святом Різдва! Зичимо всім українцям довгожданого миру, міцного здоровʼя, злагоди, родинного затишку та втілення всього доброго і прекрасного, чого вам побажали колядники!

    Теми цього довгочиту:

    Різдво
  • Каблучки – прикраси, які варто купувати

    Ювелірні вироби – це не тільки спосіб витратити гроші, але і зробити вигідні інвестиції. Бо вартість ювелірних виробів з кожним роком тільки зростає. Тому купуючи стильні прикраси, ви вигідно вкладаєте кошти.

    Теми цього довгочиту:

    Як Вибрати Каблучку
  • П'ять помилок у виборі домашнього текстилю, які псують комфорт сну

    Навіть ідеальний матрац не компенсує дискомфорт, якщо текстиль підібрано неправильно. Постільна білизна безпосередньо впливає на терморегуляцію, стан шкіри та глибину сну. Більшість проблем виникає не через низьку якість виробів, а через вибір матеріалів та подальшу експлуатацію

    Теми цього довгочиту:

    Домашній Текстиль
  • Як знайти житло в Києві

    Переїжджаєте до Києва і шукаєте житло? Дізнайтеся, як орендувати чи купити квартиру, перевірити власника та знайти варіанти, про які зазвичай не говорять.

    Теми цього довгочиту:

    Агентство Нерухомості
  • Як заохотити дитину до читання?

    Як залучити до читання сучасну молодь - поради та факти. Користь читання для дітей - основні переваги. Розвиток дітей - це наше майбутнє.

    Теми цього довгочиту:

    Читання
Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Вітя
Вітя@kor0p

Python SDET @ ajax.systems

850Прочитань
10Автори
18Читачі
Підтримати
На Друкарні з 14 квітня

Більше від автора

Це також може зацікавити:

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Це також може зацікавити: