Декораторы
Напоминание
Абстракция и композиция
Статические и динамические поля
Рекомендации к созданию классов
Статические методы
Пример
Вложенные функции
Пример
Пример декоратора
Декоратор в действии
Еще пример
Аргументы и возвращаемые значения
Декораторы с аргументами
Декоратор-класс
Документация
Встроенные декораторы
@classmethod и @staticmethod
Декоратор @property
905.14K
Category: programmingprogramming

Декораторы

1. Декораторы

2. Напоминание

• Инкапсуляция: объединение данных и методов, которые
работают с этими данными, в одном классе и скрытие их от
остального кода.
• Наследование: возможность создавать новые классы на основе
уже существующих и наследовать их свойства и методы.
• Полиморфизм: возможность объектов с одинаковым
интерфейсом иметь разные реализации методов.

3.

4. Абстракция и композиция

• Абстракция: создание упрощенной модели объекта, которая
позволяет сосредоточиться на основных характеристиках
объекта, игнорируя мелкие детали. Абстракция позволяет
разрабатывать более гибкие и масштабируемые программы.
• Композиция: создание нового объекта путем объединения уже
существующих объектов. Композиция позволяет создавать
объекты, которые могут выполнять сложные задачи, используя
функциональность других объектов.

5.

• Aбстракция позволяет:
Выделить главные и наиболее значимые свойства предмета.
• Отбросить второстепенные характеристики.
• Когда мы имеем дело с составным объектом - мы прибегаем к
абстракции. Например, мы должны понимать, что перед нами
абстракция, если мы рассматриваем объект как "дом", а не
совокупность кирпича, стекла и бетона. А если уже представить
множество домов как "город", то мы снова приходим к абстракции, но
уже на уровень выше.
Зачем нужна абстракция? Если мыслить масштабно - то она позволяет
бороться со сложностью реального мира. Мы отбрасываем все
лишнее, чтобы оно нам не мешало, и концентрируемся только на
важных чертах объекта.

6. Статические и динамические поля

7. Рекомендации к созданию классов

• Создавайте классы, которые отвечают только за одну задачу, и
следуйте принципу единственной ответственности.
• Используйте наследование, чтобы избежать дублирования кода и
упростить его поддержку.
• Используйте полиморфизм, чтобы обеспечить гибкость кода и
упростить его использование.
• Используйте инкапсуляцию, чтобы скрыть детали реализации и
обеспечить безопасность кода.
• Помните, что классы должны моделировать реальные объекты и
процессы, а не только выполнять задачи.
• Документируйте каждый класс и его методы, чтобы облегчить его
использование другими разработчиками.

8.

• Чтобы избежать создания слишком сложных и неструктурированных классов, можно
использовать следующие советы:
• Разбейте класс на более мелкие подклассы, каждый из которых решает отдельную задачу.
• Используйте наследование, чтобы избежать дублирования кода.
• Избегайте сильной связности между классами, чтобы классы были более переносимыми и
гибкими.
• Не добавляйте в классы функциональность, которая не относится к их основной задаче.
• Избегайте создания слишком многих методов и атрибутов в классе, чтобы класс был проще
в использовании и понимании.
• Используйте исключения, чтобы сообщать об ошибках внутри класса, вместо того, чтобы
просто возвращать ошибочное значение.
• Разделяйте классы на слои, чтобы каждый слой решал свою задачу, и классы внутри слоя
имели схожую функциональность.

9.

• Еще одной особенностью ООП в Python является наличие
магических методов, которые позволяют определять поведение
объектов в различных ситуациях. Например, метод __str__
определяет строковое представление объекта, а метод __len__
определяет длину объекта. Магические методы позволяют
создавать более гибкие и мощные объекты, но их неправильное
использование может привести к сложностям в понимании кода.

10. Статические методы

• Статические методы - это обычные функции, которые помещены в
класс для удобства и тем самым располагаются в области видимости
этого класса. Чаще всего это какой-то вспомогательный код.
Важная особенность заключается в том, что данные методы можно
вызывать посредством обращения к имени класса, создавать объект
класса при этом не обязательно. Именно поэтому в таких методах не
используется self - этому методу не важна информация об объектах
класса.
Чтобы создать статический метод в Python, необходимо
воспользоваться специальным декоратором - @staticmethod.
Выглядит это следующим образом:

11.

• В Python также есть возможность использовать декораторы,
которые позволяют модифицировать поведение методов и
классов. Например, декоратор @property позволяет использовать
метод как атрибут, а декоратор @staticmethod позволяет
определить статический метод, который не имеет доступа к
атрибутам и методам объекта.

12.

• Декораторы – это обертка вокруг функций (или классов) в Python,
которая меняет способ работы этой функции.

13. Пример

def myfunction():
print('hello')
print(type(myfunction))
> <class 'function'>

14.

class myclass:
a='hello'
def myfunction():
s= myclass.a
print(s)
print(type(myclass))
> <class 'type'>

15.

• Мы можем сохранять функции в переменные, передавать их в
качестве аргументов и возвращать из других функций. Можно
даже определить одну функцию внутри другой. Иными словами,
функции — это объекты первого класса.

16. Вложенные функции

def wrapperfuntcion():
def level1function():
def level2function():
return 'Hello'
return level2function()+' World'
return level1function()+'!'
print(wrapperfuntcion())

17. Пример

def func1(z):
z()
def func2():
print('hello')
func1(func2)

18. Пример декоратора

def decorator_function(func):
def wrapper():
print('Функция-обёртка!')
print('Оборачиваемая функция: {}'.format(func))
print('Выполняем обёрнутую функцию...')
func()
print('Выходим из обёртки')
return wrapper

19.

• Здесь decorator_function() является функцией-декоратором. Как
вы могли заметить, она является функцией высшего порядка, так
как принимает функцию в качестве аргумента, а также
возвращает функцию. Внутри decorator_function() мы определили
другую функцию, обёртку, так сказать, которая обёртывает
функцию-аргумент и затем изменяет её поведение.

20. Декоратор в действии

@decorator_function
def hello_world():
print('Hello world!')
hello_world()

21.

22.

• Просто добавив @decorator_function перед определением
функции hello_world(), мы модифицировали её поведение,
выражение с @ является всего лишь синтаксическим сахаром для
hello_world = decorator_function(hello_world).

23.

24. Еще пример

def benchmark(func):
import time
def wrapper():
start = time.time()
func()
end = time.time()
print('[*] Время выполнения: {} секунд.'.format(end-start))
return wrapper
@benchmark
def fetch_webpage():
import requests
webpage = requests.get('https://yandex.ru')
fetch_webpage()

25. Аргументы и возвращаемые значения

def benchmark(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
return_value = func(*args, **kwargs)
end = time.time()
print('[*] Время выполнения: {} секунд.'.format(end-start))
return return_value
return wrapper
@benchmark
def fetch_webpage(url):
import requests
webpage = requests.get(url)
return webpage.text
webpage = fetch_webpage('https://yandex.ru')
print(webpage)

26.

27.

• Как вы видите, аргументы декорируемой функции передаются
функции-обёртке, после чего с ними можно делать что угодно.
Можно изменять аргументы и затем передавать их декорируемой
функции, а можно оставить их как есть или вовсе забыть про них
и передать что-нибудь совсем другое. То же касается
возвращаемого из декорируемой функции значения, с ним тоже
можно делать что угодно.

28. Декораторы с аргументами

def benchmark(iters):
def actual_decorator(func):
import time
def wrapper(*args, **kwargs):
total = 0
for i in range(iters):
start = time.time()
return_value = func(*args, **kwargs)
end = time.time()
total = total + (end-start)
print('[*] Среднее время выполнения: {} секунд.'.format(total/iters))
return return_value
return wrapper
return actual_decorator
@benchmark(iters=3)
def fetch_webpage(url):
import requests
webpage = requests.get(url)
return webpage.text
webpage = fetch_webpage('https://google.com')

29.

• Здесь мы модифицировали наш старый декоратор таким образом,
чтобы он выполнял декорируемую функцию iters раз, а затем выводил
среднее время выполнения. Однако чтобы добиться этого, пришлось
воспользоваться природой функций в Python.
• Функция benchmark() на первый взгляд может показаться
декоратором, но на самом деле таковым не является. Это обычная
функция, которая принимает аргумент iters, а затем возвращает
декоратор. В свою очередь, он декорирует функцию fetch_webpage().
Поэтому мы использовали не выражение @benchmark, а
@benchmark(iters=3) — это означает, что тут вызывается функция
benchmark() (функция со скобками после неё обозначает вызов
функции), после чего она возвращает сам декоратор.

30.

def decorator(func):
'''Основная функция'''
print('1. Декоратор')
def wrapper():
print('3. до функции', func.__name__)
func()
print('5. после функции', func.__name__)
return wrapper
print('0. Начало')
@decorator
def wrapped():
print('4. Обернутая функция')
print('2. старт программы...')
wrapped()
print('- конец программы')

31. Декоратор-класс

class myclassdecorator:
def __init__(self, func):
print('Класс Decorator метод __init__')
self.func = func
def __call__(self):
print('перед вызовом класса...', self.func.__name__)
self.func()
print('после вызова класса')
@myclassdecorator
def wrapped():
print('функция wrapped')
print('старт')
wrapped()
print('конец')

32.

• Отличие в том, что класс инициализируется при объявлении. Он
должен получить функцию в качестве аргумента для метода
__init__. Это и будет декорируемая функция.
• При вызове декорируемой функции на самом деле вызывается
экземпляр класса. А поскольку объект вызываемый, то
вызывается функция __call__.

33. Документация

• Один из атрибутов функции — строка документации (docstring),
доступ к которой можно получить с помощью __doc__. Это
строковая константа, определяемая как первая инструкция в
объявлении функции.

34. Встроенные декораторы

• Python содержит несколько встроенных декораторов. Из всех
этих декораторов, самой важной троицей являются:
• @classmethod
• @staticmethod
• @property
• Также существуют декораторы в различных разделах стандартной
библиотеки Python. Одним из примеров является functools.wraps.
Мы сосредоточимся на трех главных декораторах, указанных
выше.

35. @classmethod и @staticmethod

• Декоратор <*@classmethod>* может быть вызван при помощи экземпляра
класса, или напрямую, через собственный класс Python в качестве первого
аргумента. В соответствии с документацией Python: он может быть вызван
как в классе (например, C.f()), или в экземпляре (например, C().f()).
Экземпляр игнорируется, за исключением его класса. Если метод класса
вызван для выведенного класса, то объект выведенного класса
передается в качестве подразумеваемого первого аргумента.
• Декоратор @classmethod, в первую очередь, используется как чередуемый
конструктор или вспомогательный метод для инициализации.
• Декоратор <*@staticmethod>* — это просто функция внутри класса. Вы
можете вызывать их обоих как с инициализацией класса так и без создания
экземпляра класса. Обычно это применяется в тех случаях, когда у вас есть
функция, которая, по вашему убеждению, имеет связь с классом. По
большей части, это выбор стиля.

36.

37. Декоратор @property

class Rectangle:
def __init__(self, a, b):
self.a = a
self.b = b
@property
def area(self):
return self.a * self.b
rect = Rectangle(5, 6)
print(rect.area)

38.

• Один из самых простых способов использования property, это
использовать его в качестве декоратора метода. Это позволит
вам превратить метод класса в атрибут класса. Для меня это было
очень полезно, когда мне нужно сделать какую-нибудь
комбинацию значений.
English     Русский Rules