Начнем с 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
Здесь мы можем сказать, что функция decorator изменила нашу функцию 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()
Завершим все, чем с кейсом, но перед этим поговорим о некоторых людях.
Методы получения и установки используются во многих объектно-ориентированных языках программирования для обеспечения принципа инкапсуляции данных (рассматривается как связывание данных с методами, которые работают с этими данными).
Эти методы, конечно, являются средством получения данных и средством изменения данных.
Согласно этому принципу атрибуты класса делаются закрытыми, чтобы скрыть их и защитить от другого кода.
Да, @property - это в основном питонический способ использования геттеров и сеттеров.
У 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 property () - это встроенная функция, которая создает и возвращает объект свойства.
У объекта свойства есть три метода: 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_tength остается свойством вместо метода.
Теперь вы можете получить доступ к значению температуры, написав.
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
Кроме того, мы можем продолжить и не определять имена get_teuration и set_tempera, поскольку они не нужны и загрязняют пространство имен класса.
Вещий способ справиться с указанной выше проблемы является использование @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 температура (self)» и «def температура (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
Это здорово, не правда ли: вы можете начать с самой простой реализации, какой только можно себе представить, и вы можете позже перейти на версию свойства без необходимости менять интерфейс! Так что свойства - это не просто замена геттерам и сеттерам!
Вы можете проверить эту реализацию здесь