Зачем нужен декоратор property python

Работа декоратора @property в Python

Существует ряд функциональных возможностей в Python, которые могут вызвать вопросы у новичков. Одной из таких является функция property , которую можно использовать как встроенную функцию, так и в качестве декоратора.

Для начала рассмотрим простой пример использования property как встроенной функции:

class MyClass: def __init__(self): self._value = None def get_value(self): return self._value def set_value(self, value): self._value = value def del_value(self): del self._value value = property(get_value, set_value, del_value, "This is 'value' property.")

Здесь property принимает четыре аргумента: метод для получения значения ( get_value ), метод для установки значения ( set_value ), метод для удаления значения ( del_value ) и строку документации.

Теперь рассмотрим пример использования property как декоратора:

class MyClass: def __init__(self): self._value = None @property def value(self): """This is 'value' property.""" return self._value @value.setter def value(self, value): self._value = value @value.deleter def value(self): del self._value

В данном примере property используется как декоратор для функции value . Но как создаются декораторы value.setter и value.deleter в этом случае?

В действительности, property в Python это не просто функция, а так называемый дескриптор. Дескрипторы — это особые объекты, которые имеют методы __get__ , __set__ и __delete__ . Метод __get__ вызывается при доступе к значению атрибута, __set__ — при присваивании значения атрибуту, а __delete__ — при удалении атрибута.

Когда property используется как декоратор, он возвращает новый объект свойства с методом __get__ , который связан с декорируемой функцией. Этот новый объект свойства имеет методы setter и deleter , которые принимают функцию и возвращают новый объект свойства, связанный с этой функцией.

Читайте также:  Php получить файл и сохранить

Таким образом, когда мы пишем @value.setter , мы фактически создаем новый объект свойства с методом __set__ , связанным с функцией, которую мы декорируем. Аналогично, @value.deleter создает новый объект свойства с методом __delete__ .

С помощью декоратора property мы можем сделать методы класса доступными как обычные атрибуты, что упрощает их использование.

Источник

Как использовать декоратор свойств Python?

В Python есть очень полезная функция, называемая декораторами, которая является всего лишь синтаксической для оберток функций. Здесь мы сосредоточимся на декораторе свойств, который представляет собой особый тип декоратора.

Эта тема может вас немного запутать, поэтому мы рассмотрим ее шаг за шагом с примерами.

питон Property

На чем основан декоратор свойств Python?

Декоратор свойств основан на встроенной функции property() . Эта функция возвращает специальный объект property .

Вы можете вызвать это в своем интерпретаторе Python и посмотреть:

Этот объект property имеет несколько дополнительных методов для получения и установки значений объекта. У него также есть метод его удаления.

Список методов приведен ниже:

Но это еще не все. Эти методы можно использовать и с другими объектами, и они сами действуют как декораторы. Так, например, мы можем использовать property().getter(obj) , что даст нам еще один объект свойства.

Итак, следует отметить, что декоратор свойств будет использовать эту функцию, которая будет иметь некоторые специальные методы для чтения и записи в объект. Но как это нам помогает?

Использование декоратора свойств Python

Чтобы использовать декоратор свойств, нам нужно обернуть его вокруг любой функции или метода.

@property def fun(a, b): return a + b
def fun(a, b): return a + b fun = property(fun)

Итак, здесь мы оборачиваем property() вокруг fun() , что и делает декоратор. Давайте теперь рассмотрим простой пример, используя декоратор свойств в методе класса.

Рассмотрим приведенный ниже класс без каких-либо декорированных методов:

class Student(): def __init__(self, name, id): self.name = name self.id = id self.full_id = self.name + " - " + str(self.id) def get_name(self): return self.name s = Student("Amit", 10) print(s.name) print(s.full_id) # Change only the name s.name = "Rahul" print(s.name) print(s.full_id)
Amit Amit - 10 Rahul Amit - 10

Здесь, как вы можете видеть, когда мы изменяем только атрибут name нашего объекта, ссылка на атрибут full_id все еще не обновляется.

Чтобы гарантировать, что атрибут full_id также обновляется всякий раз, когда обновляется name или id , можно было бы вместо этого превратить full_id в метод.

class Student(): def __init__(self, name, id): self.name = name self.id = id def get_name(self): return self.name # Convert full_id into a method def full_id(self): return self.name + " - " + str(self.id) s = Student("Amit", 10) print(s.name) # Method call print(s.full_id()) s.name = "Rahul" print(s.name) # Method call print(s.full_id())
Amit Amit - 10 Rahul Rahul - 10

Здесь мы решили нашу проблему, преобразовав full_id в метод full_id() .

Однако это не лучший способ решить эту проблему, поскольку вместо этого вам может потребоваться преобразовать все такие атрибуты в метод и изменить атрибуты в вызовы методов. Это не удобно.

Мы можем использовать вместо этого декоратор @property .

Идея состоит в том, чтобы превратить full_id() в метод, но заключить его с помощью @property . Таким образом, мы сможем обновить full_id без необходимости рассматривать его как вызов функции.

Мы можем сделать это напрямую: s.full_id . Обратите внимание, что здесь нет вызова метода. Это из-за декоратора свойств.

Давайте попробуем прямо сейчас.

class Student(): def __init__(self, name, id): self.name = name self.id = id def get_name(self): return self.name @property def full_id(self): return self.name + " - " + str(self.id) s = Student("Amit", 10) print(s.name) # No more method calls! print(s.full_id) s.name = "Rahul" print(s.name) # No more method calls! print(s.full_id)
Amit Amit - 10 Rahul Rahul - 10

Действительно, теперь это работает. Теперь нам не нужно вызывать full_id используя круглые скобки.

Хотя это все еще метод, декоратор свойств маскирует его и обрабатывает так, как если бы это было свойство класса.

Использование свойства с сеттером

В приведенном выше примере подход сработал, потому что мы явно не full_id свойство full_id напрямую. По умолчанию использование @property делает это свойство доступным только для чтения.

Это означает, что вы не можете явно изменить свойство.

s.full_id = "Kishore" print(s.full_id)
---> 21 s.full_id = "Kishore" 22 print(s.full_id) AttributeError: can't set attribute

Очевидно, у нас нет разрешений, поскольку свойство доступно только для чтения.

Чтобы сделать свойство доступным для записи, вспомните метод property().setter о котором мы говорили, который также является декоратором.

Оказывается, мы можем добавить еще full_id свойство @full_id.setter , используя @full_id.setter , чтобы сделать его доступным для записи. @full_id.setter унаследует все, что есть в исходном full_id , поэтому мы можем добавить его напрямую.

Однако мы не можем напрямую использовать свойство full_id в нашем свойстве установки. Обратите внимание, что это приведет к бесконечному спуску рекурсии в Python.

class Student(): def __init__(self, name, id): self.name = name self.id = id def get_name(self): return self.name @property def full_id(self): return self.name + " - " + str(self.id) @full_id.setter def full_id(self, value): # Infinite recursion depth! # Notice that you're calling the setter property of full_id() again and again self.full_id = value

Чтобы этого избежать, мы добавим в наш класс скрытый атрибут _full_id . @property декоратор, чтобы вместо этого он возвращал этот атрибут.

Обновленный код теперь будет выглядеть так:

class Student(): def __init__(self, name, id): self.name = name self.id = id self._full_id = self.name + " - " + str(self.id) def get_name(self): return self.name @property def full_id(self): return self._full_id @full_id.setter def full_id(self, value): self._full_id = value s = Student("Amit", 10) print(s.name) print(s.full_id) s.name = "Rahul" print(s.name) print(s.full_id) s.full_id = "Kishore - 20" print(s.name) print(s.id) print(s.full_id)
Amit Amit - 10 Rahul Amit - 10 Rahul 10 Kishore - 20

Надеюсь, я понятно объяснил про декоратор свойств, а также, почему вам может потребоваться использовать атрибуты класса, такие как _full_id .

Эти скрытые атрибуты класса (например, _full_id ) позволяют нам очень легко использовать внешние свойства. Именно поэтому свойства широко используются в современных проектах с открытым исходным кодом.

Они упрощают задачу для конечного пользователя, а также позволяют разработчикам легко отделить скрытые атрибуты от не скрытых свойств.

Источник

Оцените статью