Connect with us

Обучение

Заметки Python #21: Декораторы

236

 

Декораторы одна из наиболее спорных и интересных тем в Python-сообществе. Ей посвящены десятки статей на хабре, но многие так и не могут понять до конца — зачем нужны декораторы?

Теория

Понятие работы декораторов в питоне начинается с одной базовой концепцией этого языка программирования — в Python все функции являются объектами. Это значит, что любая функция может быть привязана к переменной или быть возвращена другой функцией и стать аргументом. Всё это хорошо демонстрируют примеры:

[adace-ad id=»3482″]

 

#1 Функция = объект [code]

def function (whisky=»Lawsons Spiced»):
return whisky.capitalize() + «!»

print (function())
# выведет: ‘Lawsons spiced!’

# Так как функция — это объект, мы привязываем её к переменной, например, drinks
drinks = function

# Заметьте, что мы не используем скобок: мы НЕ вызываем функцию «functions»,
# мы связываем её с переменной «drinks». Это означает, что теперь мы
# можем вызывать «functions» через «drinks»:

print (drinks())
# выведет: ‘Lawsons spiced!’

# Более того, это значит, что мы можем удалить «shout», и функция всё ещё
# будет доступна через переменную «scream»

del function
try:
print (function)
except NameError:
print («Нет такой функции больше»)
# выведет: «Нет такой функции больше»

print (drinks())
# выведет: ‘Lawsons spiced!’

[/code]

 

Результат:

#2 Определение функции внутри другой функции [code]

def alcohol():
# Внутри определения функции «алкоголь» мы можем определить другую…
def areyousure(word=»БУДУ!»):
return word.upper() + «…»

# … и сразу же её использовать!
print (areyousure())

# Теперь, КАЖДЫЙ РАЗ при вызове «Alcohol», внутри неё определяется а затем
# и вызывается функция «areyousure».
alcohol()
# выведет: «БУДУ!»

# Но вне функции «Alcohol» НЕ существует никакой функции «areyousure»:
try:
print (areyousure)
except NameError:
print («Нет такой функции»)
# выведет : «name ‘whisper’ is not defined»

[/code]

 

Результат

#3 Функция возвращает другую функцию [code]

def getTalk(type=»shout»):

# Мы определяем функции прямо здесь
def shout(word=»да»):
return word.capitalize()+»!»

def whisper(word=»да») :
return word.lower()+»…»;

# Затем возвращаем необходимую
if type == «shout»:
# Заметьте, что мы НЕ используем «()», нам нужно не вызвать функцию,
# а вернуть объект функции
return shout
else:
return whisper

# Как использовать это непонятное нечто?
# Возьмём функцию и свяжем её с переменной
talk = getTalk()

# Как мы можем видеть, «talk» теперь — объект «function»:
print talk
# выведет: <function shout at 0xb7ea817c>

# Который можно вызывать, как и функцию, определённую «обычным образом»:
print talk()

# Если нам захочется — можно вызвать её напрямую из возвращаемого значения:
print getTalk(«whisper»)()
# выведет: да…

[/code]

 

Результат

[adace-ad id=»3475″]

 

#4 Передача функции, как параметр другой функции [code]

def function (whisky=»Lawsons Spiced»):
return whisky.capitalize() + «!»

def function2(func):
print («Я буду пить только»)
print (func())

function2(function)
# выведет:
# Я делаю что-то ещё, перед тем как вызвать функцию, которую ты мне передал
# Lawsons spiced!

[/code]

 

Результат

Практика

Последним примером мы напрямую подобрались к самой сути декоратора — «обёртки» для другой функции. С его помощью мы будем форматировать и рефакторить наш код

#5 Декоратор в действии [code]

# Декоратор — это функция, ожидающая ДРУГУЮ функцию в качестве параметра
def Alcohol(Whisky):
# Внутри себя декоратор определяет функцию-«обёртку».
# Она будет обёрнута вокруг декорируемой,
# получая возможность исполнять произвольный код до и после неё.

def drinks_whisky():
# Поместим здесь код, который мы хотим запускать ДО вызова
# оригинальной функции
print («Тут я еще трезвый»)

# ВЫЗОВЕМ саму декорируемую функцию
Whisky()

# А здесь поместим код, который мы хотим запускать ПОСЛЕ вызова
# оригинальной функции
print («Ох, епт, я в мясо»)

# На данный момент функция «Whisky» НЕ ВЫЗЫВАЛАСЬ НИ РАЗУ

# Теперь, вернём функцию-обёртку, которая содержит в себе
# декорируемую функцию, и код, который необходимо выполнить до и после.
# Всё просто!
return drinks_whisky()

# Представим теперь, что у нас есть функция, которую мы не планируем больше трогать.
def party():
print («Бухаю вискарь!УУхууу!»)

party()
# выведет: Бухаю вискарь!УУхууу!

# Однако, чтобы изменить её поведение, мы можем декорировать её, то есть
# Просто передать декоратору, который обернет исходную функцию в любой код,
# который нам потребуется, и вернёт новую, готовую к использованию функцию:

party = Alcohol(party)
# Теперь поведение вывода party изменится, т.к. она задекорирована
print (party)

# выведет:
# Тут я еще трезвый
# Бухаю вискарь!УУхууу!
# Ох, епт, я в мясо

# Если записать проще, в виде декоратора, то код будет выглядеть вот так:
@Alcohol
def party():
print («Бухаю вискарь!УУхууу!»)

print(party)

# выведет:
# Тут я еще трезвый
# Бухаю вискарь!УУхууу!
# Ох, епт, я в мясо

[/code]

 

Результат:

[adace-ad id=»3470″]

 

В питоне так же есть и встроенные декораторы: @classmethod, @staticmethod, @property. А еще можно вызывать один декоратор за другим

#6 Использование нескольких декораторов [code]

def bread(func):
def wrapper():
print («</——\>»)
func()
print («<\______/>»)

return wrapper

def ingredients(func):
def wrapper():
print («#помидоры#»)
func()
print («~салат~»)

return wrapper

def sandwich(food=»—ветчина—«):
print (food)

sandwich()
# выведет: —ветчина—
sandwich = bread(ingredients(sandwich))
sandwich()
# выведет:
# </——\>
# #помидоры#
# —ветчина—
# ~салат~
# <\______/>

# ——————————- А теперь сделаем это через декораторы
# ——— Важна последовательность вызова декораторов
# — То есть внутри bread будет ingredients, внутри которого будет sandwich
@bread
@ingredients
def sandwich(food=»—ветчина—«):
print (food)

sandwich()
# выведет:
# </——\>
# #помидоры#
# —ветчина—
# ~салат~
# <\______/>

[/code]

 

Результат:

Нажмите что бы оставить комментарий

Ответить

Ваш адрес email не будет опубликован.

Лучшие сервисы стриминга музыки в 2019 году

Сервисы

Телевидение Wink Ростелеком: Samsung LG, Sony, Phillips, Android TV

Ростелеком

Ноутбуки Asus не видят жесткий диск. Автоматический вход в BIOS при старте

Гаджеты

LG WEB OS: приложения, обновления, настройка, проблемы со звуком

Гаджеты

Advertisement Яндекс.Метрика

Digital2.ru - Тренды, Профессии IT, WEB- разработка, Вакансии, Автоматизация, Цифровая экономика
Свободное копирование и распространение материалов с сайта Digital2.ru
разрешено только с указанием активной ссылки на Digital2 как на источник.
Copyright 2018 - 2020 © All rights reserved

OPGIO.COM

Connect