Property в Python
Что такое property()? Функция используется для определения свойств в классах. Метод property() обеспечивает интерфейс для атрибутов экземпляра класса.
Он инкапсулирует атрибуты экземпляров и предоставляет свойства, аналогично тому, как это работает в Java и C#. Метод property() принимает на вход методы get, set и delete, и возвращает объекты класса property.
Давайте рассмотрим простой код без Property на примере класса, принимающего имя и возраст.
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self, age):
self.__age = age
Мы создали приватные age и name, и давайте попробуем задать значения и вывести в консоль
p = Person('Владислав', 23)
p.set_age(24)
print(p.get_age())
Получаем результат:
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
24
Process finished with exit code 0
Как видим, мы задали set_age 24 и его получили. А теперь представьте, что для каждой такой инициализации придется писать set_age много раз для многих других персон. Поэтому приходит к нам на помощь свойства Property
У нас есть ведь два метода, верно? Давайте сделаем следующее:
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self, age):
self.__age = age
age = property(get_age, set_age)
В этом случае, нам не нужно запоминать постоянно имена наших геттеров и сеттеров, мы можем спокойно напрямую в приватные атрибуты задавать значения таким образом:
p = Person('Владислав', 23)
p.age = 24
print(p.age)
Результат:
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
24
Process finished with exit code 0
Как видите, мы можем присвоить p.age = 24, это отработает наш set_age, а можем вывести, без скобок p.age - это отработает наш get_age с помощью Property. К тому же, приоритет такого атрибута намного выше, чем у любого локального свойства, которое может присутствовать в экземпляре класса, даже с таким же названием свойства.
Можно сделать ещё следующим образом:
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def get_age(self):
return self.__age
@get_age.setter
def get_age(self, age):
self.__age = age
p = Person('Владислав', 23)
p.get_age = 24
print(p.__dict__)
У Property есть свои декораторы, а именно getter, setter, deleter. Мы можем сделать такой единый удобный интерфейс.
А давайте сделаем приближенно к первому варианту:
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
p = Person('Владислав', 23)
p.age = 24
print(p.__dict__)
Результат:
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
{'_Person__name': 'Владислав', '_Person__age': 24}
Process finished with exit code 0
Таким образом, мы избавились от функционального дублирования.
Давайте ещё добавим deleter:
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
@age.deleter
def age(self):
del self.__age
p = Person('Владислав', 23)
del p.age
print(p.age, p.__dict__)
И так как у нас не будет приватного атрибута age, мы получим ошибку:
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
Traceback (most recent call last):
File "C:\Users\Razilator\Desktop\Courses\nth-coding\main.py", line 25, in <module>
print(p.age, p.__dict__)
File "C:\Users\Razilator\Desktop\Courses\nth-coding\main.py", line 11, in age
return self.__age
AttributeError: 'Person' object has no attribute '_Person__age'. Did you mean: '_Person__name'?
Process finished with exit code 1
Но если мы просто покажем __dict__, то выведется следующее, уже без age
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
{'_Person__name': 'Владислав'}
Process finished with exit code 0
А чтоб задать обратно, после удаления, то можно прописать наш setter:
p = Person('Владислав', 23)
del p.age
p.age = 25
print(p.__dict__)
Результат:
C:\Users\Razilator\Desktop\Courses\nth-coding\venv\Scripts\python.exe C:/Users/Razilator/Desktop/Courses/nth-coding/main.py
{'_Person__name': 'Владислав', '_Person__age': 25}
Process finished with exit code 0
Вот с такой легкостью можно работать с приватными закрытыми локальными свойствами через объект свойства Property.
Урок взят с канала selfedu