Декоратор property в Python

Содержание
Введение
Предпосылки
Пример
setter
deleter
Полный код примера
Похожие статьи

Введение

Это продолжение статьи «Классы» из раздела «ООП в Python» .

Для лучшего понимания этого материала пригодятся знания из следующих статей: Методы , Класс методы , Статические методы , super() , Декораторы , isinstance()

Партнёром этой статьи будем считать моего хостинг-провайдера beget.com

Предпосылки

Рассмотрим простой класс

class Employee: def __init__(self, first, last): self.first = first self.last = last self.email = first + '.' + last + '@beget.com' def fullname(self): return f'{self.first} {self.last}' emp_1 = Employee("Ivan", "Petrov") print(emp_1.first) print(emp_1.email) print(emp_1.fullname())

python property_deco.py

Ivan Ivan.Petrov@beget.com Ivan Petrov

Изменим только атрибут first у emp_1 и посмотрим как преобразится вывод

class Employee: def __init__(self, first, last): self.first = first self.last = last self.email = first + '.' + last + '@beget.com' def fullname(self): return f'{self.first} {self.last}' emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.first = 'Andrei' print(emp_1.first) print(emp_1.email) print(emp_1.fullname())

python property_deco.py

Andrei Ivan.Petrov@beget.com Andrei Petrov

Как видите, email остался прежним, как-будто работника по-прежнему зовут Иван. Это атрибут был создан вместе с объектом и больше его никто не трогал.

fullname обновился, так как этот метод каждый раз переиспользует текущие атрибуты.

Что делать если нужно автоматически обновлять email?

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

Обратите внимание на вызов метода - нужно везде добавить ()

class Employee: def __init__(self, first, last): self.first = first self.last = last # self.email = first + "." + last + "@beget.com" def fullname(self): return f"{self.first} {self.last}" def email(self): return f"{self.first}.{self.last}@beget.com" emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.first = "Andrei" print(emp_1.first) print(emp_1.email()) print(emp_1.fullname())

python property_deco.py

Andrei Andrei.Petrov@beget.com Andrei Petrov

Оставить и метод и атрибут с тем же название нельзя - получим ошибку TypeError: 'str' object is not callable

Andrei Traceback (most recent call last): File "/home/andrei/python/property_deco.py", line 21, in <module> print(emp_1.email()) TypeError: 'str' object is not callable

Пример

Если написать метод email() и добавить к нему декоратор @property обратная совместимость не пострадает.

class Employee: def __init__(self, first, last): self.first = first self.last = last def fullname(self): return f"{self.first} {self.last}" @property def email(self): return f"{self.first}.{self.last}@beget.com" emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.first = "Andrei" print(emp_1.first) print(emp_1.email) print(emp_1.fullname())

python property_deco.py

Andrei Andrei.Petrov@beget.com Andrei Petrov

setter

Добавим декоратор @property к обоим методам и попробуем задать fullname

class Employee: def __init__(self, first, last): self.first = first self.last = last @property def fullname(self): return f"{self.first} {self.last}" @property def email(self): return f"{self.first}.{self.last}@beget.com" emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.fullname = "Andrei Olegovich" print(emp_1.first) print(emp_1.email) print(emp_1.fullname)

python property_deco.py

Traceback (most recent call last): File "/home/andrei/python/property_deco.py", line 21, in <module> emp_1.fullname = "Andrei Olegovich" AttributeError: can't set attribute

Избавиться от ошибки поможет декоратор setter

@fullname.setter def fullname(self, name): first, last = name.split(' ') self.first = first self.last = last emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.fullname = "Andrei Olegovich" print(emp_1.first) print(emp_1.email) print(emp_1.fullname)

python property_deco.py

Andrei Andrei.Petrov@beget.com Andrei Petrov

deleter

Удалить атрибут лучше всего с помощью декоратора deleter

@fullname.deleter def fullname(self): print("Delete Name!") self.first = None self.last = None emp_1.fullname = "Andrei Olegovich" print(emp_1.first) print(emp_1.email) print(emp_1.fullname) del emp_1.fullname print(emp_1.fullname)

python property_deco.py

Andrei Andrei.Olegovich@beget.com Andrei Olegovich Delete Name! None None

Полный код примера

class Employee: def __init__(self, first, last): self.first = first self.last = last @property def email(self): return f"{self.first}.{self.last}@beget.com" @property def fullname(self): return f"{self.first} {self.last}" @fullname.setter def fullname(self, name): first, last = name.split(' ') self.first = first self.last = last @fullname.deleter def fullname(self): print("Delete Name!") self.first = None self.last = None emp_1 = Employee("Ivan", "Petrov") # Change the attribute emp_1.fullname = "Andrei Olegovich" print(emp_1.first) print(emp_1.email) print(emp_1.fullname) del emp_1.fullname print(emp_1.fullname)

Похожие статьи
ООП в Python
Классы
Методы
class variables
class methods
Статические методы
Наследование
Специальные методы
Декоратор property
Python
Функции
super()
Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@eth1.ru если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящуюю по тематике.
3. Хотите поддержать сайт материально
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......