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

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

Запись от Фаер размещена 13.11.2012 в 16:00
Показов 4654 Комментарии 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
Комментарии
 
Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru