Почнемо з декораторів Python.
Прикрасник Python - це функція, яка допомагає додати деякі додаткові функції до вже визначеної функції.
У Python все є об’єктом. Функції в Python - це об'єкти першого класу, що означає, що на них можна посилатися змінною, додавати в списки, передавати як аргументи іншій функції тощо.
Розглянемо наступний фрагмент коду.
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
def say_bye():
print("bye!!")
say_bye = decorator_func(say_bye)
say_bye()
# Output:
# Wrapper function started
# bye
# Given function decorated
Тут ми можемо сказати, що функція декоратора змінила нашу функцію say_hello і додала в неї кілька додаткових рядків коду.
Синтаксис Python для декоратора
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
@decorator_func
def say_bye():
print("bye!!")
say_bye()
Давайте зробимо висновок про все, ніж зі сценарієм випадку, але перед цим поговоримо про деякі принципи ой.
Геттери і сетери використовуються в багатьох об'єктно-орієнтованих мовах програмування для забезпечення принципу інкапсуляції даних (розглядається як поєднання даних із методами, що працюють на цих даних.)
Ці методи, звичайно, є геттером для отримання даних і сеттером для зміни даних.
Відповідно до цього принципу, атрибути класу робляться приватними, щоб приховати та захистити їх від іншого коду.
Так, @ власність - це в основному пітонічний спосіб використання геттерів та сеттерів.
У Python є чудова концепція, яка називається властивістю, яка значно спрощує життя об'єктно-орієнтованого програміста.
Припустимо, ви вирішили скласти клас, який міг би зберігати температуру в градусах Цельсія.
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
Реконструйований кодекс. Ось як ми могли його досягти майном.
У Python властивість () - це вбудована функція, яка створює та повертає об’єкт властивості.
Об'єкт властивості має три методи: getter (), setter () та delete ().
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self.temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
temperature = property(get_temperature,set_temperature)
Ось
temperature = property(get_temperature,set_temperature)
могла бути розбита як,
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
Вказати:
- get_temperature залишається властивістю замість методу.
Тепер ви можете отримати доступ до значення температури, написавши.
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
Ми можемо продовжувати і не визначати імена get_temperature та set_temperature, оскільки вони непотрібні та забруднюють простір імен класів.
Віщий спосіб впоратися з вказаною вище проблеми є використання @property .
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self.temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
Бали до примітки -
- Метод, який використовується для отримання значення, прикрашається символом "@property".
- Метод, який повинен функціонувати як сеттер, прикрашений "@ temperature.setter", Якби функція була названа "x", нам доведеться прикрасити її "@ x.setter".
- Ми написали "два" методи з однаковою назвою та різною кількістю параметрів "def temperature (self)" та "def temperature (self, x)".
Як бачите, код, безумовно, менш елегантний.
Тепер поговоримо про один практичний сценарій.
Скажімо, ви створили клас таким чином:
class OurClass:
def __init__(self, a):
self.x = a
y = OurClass(10)
print(y.x)
Тепер давайте припустимо, що наш клас отримав популярність серед клієнтів, і вони почали використовувати його у своїх програмах. Вони виконували всі види завдань на об'єкт.
І одного фатального дня до нас прийшов довірений клієнт і припустив, що "х" має бути значенням від 0 до 1000, це справді жахливий сценарій!
Завдяки властивостям це легко: ми створюємо версію властивості "x".
class OurClass:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
Це чудово, чи не так: Ви можете почати з найпростішої реалізації, яку можна уявити, і ви можете пізніше перейти до версії властивості, не змінюючи інтерфейс! Тож властивості - це не просто заміна геттерам та сетерам!
Ви можете перевірити цю реалізацію тут