Форум программистов, компьютерный форум, киберфорум
Фаер
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

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

Запись от Фаер размещена 13.11.2012 в 16:00
Показов 4611 Комментарии 0

В предыдущих записях Мы говорили о клонировании и наследовании - приёмах, позволяющих изменять объекты и классы. Разумеется, Python предоставляет и другие инструменты, используя которые, можно прийти к тому же результату. Одним из таких инструментов, являются декораторы.

Декоратор - программный шаблон, оборачивающий некий объект дополнительным уровнем логики. Одним словом, обёртка. Едва ли можно сказать, что использование декораторов упрощает разработку, однако многие программисты находят их очень удобными, а значит есть смысл рассказать о них.

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
def decor(func):
    print('Done')
    return func
 
@decor
def func(t):
    t=t+5
    return t
 
otvet=func(5)
print(otvet)
input()
Как видите, декоратор decor() описывается, как самая обыкновенная подпрограмма. В качестве аргумента он принимает функцию func(), ту самую, которую Мы оборачиваем. Имя оборачивающего декоратора указывается прямо перед описанием оборачиваемой функции со значком @.

В результате, обращение к функции func происходит не напрямую, а через обёртку. В Нашем случае, сначала выполняется команда print('Done'), описанная в декораторе, а уже потом вызывается сама функция(return func).

Казалось бы, всё хорошо. Однако есть одна мелочь, которая несколько омрачает светлый образ декораторов. Дело в том, что декоратор и вложенная в него функция имеют разные пространства имён. Аргументы, переданные func(), недоступны на уровне decor'а. Исправить этот недочёт можно, но для этого нужно вложить в декоратор ещё одну функцию. Например:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def decor(func):
    def vloj(a1,a2):
        a1+=5;a2+=3
        k=func(a1,a2)
        return k
    return vloj
 
@decor
def func(a1,a2):
    t=a1+a2
    return t
 
otvet=func(0,0)
print(otvet)
input()
Мы передаём func() два нуля. Однако в декораторе описана ещё одна функция vloj(), которая перехватывает аргументы, передаваемые func(), после чего происходит изменение этих самых аргументов и их перенаправление в func():

Python
1
2
a1+=5;a2+=3
k=func(a1,a2)
В общем и целом, добавить тут больше нечего. Функции, как функции, только вложены друг в друга. Главное, не забывайте, что перехват аргументов организуется за счёт вложенной в декоратор функции, а так же не пропускайте return func, ведь описать функцию - это половина дела, её ещё надо вызвать.

Кроме декораторов функций существуют ещё декораторы классов. Возьмём старый добрый класс car(), в котором на этот раз содержится только один метод - конструктор, и посредством оборачивания добавим ему два новых метода:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def decor(clas):
    class wcar():
        def __init__(self,name,age,speed):
            self.obj=clas(name,age,speed)
            self.__dict__=self.obj.__dict__
            
        def repair(self):
            self.age-=3
        def accelerate(self):
            self.speed+=20
    return wcar
 
@decor
class car:
    def __init__(self,name,age,speed):
        self.name=name
        self.age=age
        self.speed=speed
 
c=car('Audi',8,180)
Таким образом, Мы получаем класс car(), содержащий в себе не только родные методы, но и методы, описанные в декораторе. Обратите внимание на то, что структура класса усложняется: появляется объект, вложенный в другой объект в качестве параметра. Следовательно, методы описанные в оборачиваемом классе нельзя вызвать напрямую, только через этот вложенный объект. С такой же проблемой Мы столкнулись в прошлой записи. Тогда Нам удалось разрешить ситуацию, применив наследование. Здесь тот же принцип:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def decor(clas):
    class wcar(clas):
        def __init__(self,name,age,speed):
            self.obj=clas(name,age,speed)
            self.__dict__=self.obj.__dict__    
        def repair(self):
            self.age-=3
    return wcar
 
@decor
class car:
    def __init__(self,name,age,speed):
        self.name=name
        self.age=age
        self.speed=speed
    def accelerate(self):
        self.speed+=20
Классу wcar() Мы назначаем родителя: class wcar(clas):, где clas - класс car(), переданный в декоратор в качестве аргумента.
Обратите внимание на команду return wcar - эта строка возвращает объект, сконструированный по классам car() и wcar(). Если её убрать, то результатом сборки будет объект NoneType, что Нам, конечно же, не нужно.

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def decor1(func):
    def vloj(t):
        t=t+'Stop'
        t=func(t)
        return t
    return vloj
 
def decor2(func):
    def vloj1(t):
        t=t+' it'
        t=func(t)
        return t
    return vloj1
 
@decor1
@decor2
def func(t):
    t=t+' now!'
    return t
 
r=func('')
print(r)
Вот такой получился винегрет. Вложенная в первый декоратор функция vloj(), сделав своё дело, вызывает второй декоратор, вложенная функция vloj1() которого, обработав строку t, вызывает функцию func(), вносящую последние штрихи.

Согласитесь, даже в таком простом скрипте можно напрочь запутаться. Но не забывайте, что всегда можно написать команду: print(func), которая подскажет на какую функцию ссылается данная переменная.

Таковы основы использование декораторов. Трудно назвать их самым понятным способом решения проблем, однако и обёрткам можно найти вполне достойное применение.
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
Запись в регистр сведений независимо от заполненности табличной части
Maks 25.08.2026
Реализация из решения ниже выполнена на нетиповом документе с несколькими табличными частями, разработанного в КА2. Задача: Обеспечить запись документа в регистр сведений независимо от. . .
Ноутбук Альфария
kumehtar 24.08.2026
Встретился тут в сети ноутбук Альфария, примарха Альфа-Легиона. Хотя возможно, это ноутбук Омегона, разумеется. Ну как вам?
Мастера простых решений
DevAlt 23.08.2026
В сишарп стэках winforms, да и wpf существует сложная система связывания источниках данных и элементов формы(текстовые поля и метки), опирается все это на технологию событий и мета. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru