С Новым годом! Форум программистов, компьютерный форум, киберфорум
Python
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.90/21: Рейтинг темы: голосов - 21, средняя оценка - 4.90
 Аватар для Zuzik
298 / 256 / 57
Регистрация: 11.06.2012
Сообщений: 1,557

Использование декораторов

22.02.2017, 16:18. Показов 4307. Ответов 47
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть задача сделать декоратор, который бы подключался к базе данных, выполнял некоторые действия, передавал соединение к бд и курсор во внутреннюю функцию. После выполнения функции - выполнял еще пару действий.
Написанный код.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def query_in_session(fn):
    def wrapped():
        con = cx_Oracle.connect(settings.HYDRA_CONNECTION_STRING)
 
        try:
            cur = con.cursor()
            try:
                assert isinstance(cur, cx_Oracle.Cursor)
                assert isinstance(con, cx_Oracle.Connection)
 
                cur.callproc(**settings.INIT_SESSION)
                cur.callproc(**settings.SET_ACTIVE_FIRM)
                res = fn(cur, con)
                cur.callproc(**settings.CLOSE_SESSION)
                con.commit()
            except cx_Oracle.Error:
                res = False
            finally:
                cur.close()
        except cx_Oracle.Error:
            res = False
        finally:
            con.close()
 
        return res
 
    return wrapped()
Но есть одна проблема - чтобы были доступны объект соединения с бд и курсор нужно писать вот так:
Python
1
2
3
@query_in_session
def some_sunc(cur, con):
    .....
А хочется
Python
1
2
3
@query_in_session
def some_sunc():
    .....
Можно ли так сделать?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
22.02.2017, 16:18
Ответы с готовыми решениями:

Генератор декораторов
Напишите генератор декораторов check_password, т. е. функцию, которая возвращает декоратор. Генератор декораторов принимает в качестве...

Генератор декораторов
Напишите генератор декораторов check_password, т. е. функцию, которая возвращает декоратор. Генератор декораторов принимает в качестве...

Python понимание декораторов
Всем добрый день! Начал разбираться с декораторами. В принципе, все понятно, кроме одного момента. Я понимаю, что в неправильном...

47
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
22.02.2017, 17:56
Цитата Сообщение от Zuzik Посмотреть сообщение
чтобы были доступны объект соединения с бд и курсор нужно писать вот так:
Ну да, функция явно должна принимать данные

Можно конечно вот так, но я бы так не советовал делать
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data = object
 
def my_dec(func):
    def wrapper():
        global data
        data = [1, 2, 3]
        func()
        data.clear()
    return wrapper
 
 
@my_dec
def some_func():
    print(data)
 
some_func()
0
 Аватар для Zuzik
298 / 256 / 57
Регистрация: 11.06.2012
Сообщений: 1,557
23.02.2017, 09:22  [ТС]
Цитата Сообщение от alex925 Посмотреть сообщение
Ну да, функция явно должна принимать данные
Хотелось чего либо удобного и красиво выглядящего.

Пока решил обернуть все это дело в класс. В коде пока не реализовал но в теории будет красиво, и удобно.
0
 Аватар для Zuzik
298 / 256 / 57
Регистрация: 11.06.2012
Сообщений: 1,557
24.02.2017, 09:23  [ТС]
Обернул все в класс. Вариант впринципе устроил. Плюс заодно был написан класс позволяющий более менее комфортно использовать asyncio + cx_Oracle.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
class OraclePool(object):
    """
    Класс максимально возможно реализующий асинхронный интерфейс для работы с cx_Oracle.
    Под асинхронным подразумевается asyncio-совместимый
    Единственный нюанс - пока неясно насколько быстро все это работает.
    """
 
    def __init__(self, pool: cx_Oracle.SessionPool, dbname: str = '',
                 connection: cx_Oracle.Connection = None, cursor: cx_Oracle.Cursor = None,
                 loop: asyncio.events.AbstractEventLoop = asyncio.get_event_loop(),
                 session: bool = False):
        """
        Конструктор. Ничего важного не делает.
        Проверяет, чтобы cursor и connection были None
        :param pool: пул соединений к бд
        :param dbname: наименование бд. Можно не указывать. Параметр чисто на всякий случай.
        Кандидат на удаление
        :param connection: Текущее соединение к бд. Создается автоматически при входе в блок with
        :param cursor: Текущий курсор базы данны. Создается автоматически при входе в блок with
        :param loop: Экземпляр asyncio.events.AbstractEventLoop или его наследник.\
         Нужен для определения в контексте какого loop мы выполняем код
        :param session: Выполнять ли запросы в рамках сессии. Нужно только для бд Hydra.
        """
        self.pool = pool
        self.dbname = dbname
        self.connection = connection
        self.cursor = cursor
        self.loop = loop
        self.session = session
 
        if cursor or connection:
            raise Exception('Параметры cursor и connection не должны указываться')
 
    async def execute_async(self, func, *args, **kwargs):
        """
        "Асинхронный запускатор и выполнятор" любой функции
        :param func: функция
        :param args: позиционные аргументы
        :param kwargs: именованные аргументы
        :return: результат асинхронно выполненой функции
        """
        function = partial(func, *args, **kwargs)
        f = self.loop.run_in_executor(None, function)
        data = await f
        return data
 
    async def call_proc(self, name: str, keywordparameters: dict):
        kwargs = {'name': name, 'keywordParameters': keywordparameters}
        await self.execute_async(self.cursor.callproc, **kwargs)
 
    async def __aenter__(self):
        """
        Реализация менеджера контекста, в котором осуществляется подключение к базе данных.
        Если параметр session равен True - осуществляется инициализация сессии к базе данных.
        :return:
        """
        self.connection = await self.execute_async(self.pool.acquire)
        assert isinstance(self.connection, cx_Oracle.Connection)
 
        self.cursor = await self.execute_async(self.connection.cursor)
        assert isinstance(self.cursor, cx_Oracle.Cursor)
 
        if self.session:
            await self.execute_async(self.cursor.callproc, **settings.INIT_SESSION)
            await self.execute_async(self.cursor.callproc, **settings.SET_ACTIVE_FIRM)
 
        return self
 
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """
        Реализация выхода из менеджера контекста, в котором осуществляется подключение к базе данных.
        Все возможные ошибки на текущий момент не обрабатываются.
        Для их игнорирования в функцию нужно добавить return True
        Если параметр session равен True - осуществляется закрытие сессии в базе данных.
        :param exc_type: тип исключения
        :param exc_val: экземпляр исключения
        :param exc_tb:  трейсбек исключения
        :return:
        """
        if self.session:
            await self.execute_async(self.cursor.callproc, **settings.CLOSE_SESSION)
        self.cursor.close()
        self.connection.close()
 
    @check_connection
    async def commit(self):
        """
        Функция-обертка делающая коммит в бд
        :return:
        """
        await self.execute_async(self.connection.commit)
 
    @check_connection
    async def test_query(self):
        sql = "SELECT * FROM si_v_subj_accounts WHERE VC_Account='3669143'"
        return await self.query_names(sql)
 
    @check_connection
    async def test_long_query(self):
        sql = """
        SELECT  si_ref_pkg_s.GET_NAME_BY_ID(
            SI_SUBJECTS_PKG_S.GET_SUBJ_TYPE_ID(
                SI_SUBJECTS_PKG_S.GET_BASE_SUBJECT_ID(
                    sub.N_SUBJECT_ID))) "Тип абонента",
            si_ref_pkg_s.GET_NAME_BY_ID(gv.N_REF_ID) "Тип услуги",
            sr_goods_pkg_s.GET_NAME_BY_ID(sub.N_SERVICE_ID) "Услуга",
            count(DISTINCT sub.N_DOC_ID) "Договора",count(DISTINCT sub.N_SUBSCRIPTION_ID) "Подписки"
        FROM  si_subscriptions sub
        INNER JOIN sr_good_values gv ON gv.N_GOOD_ID=sub.N_SERVICE_ID
            AND gv.N_GOOD_VALUE_TYPE_ID IN (2149605401, 2149632001, 2149755901, 2149757501)
            AND gv.C_ACTIVE='Y'
        WHERE sub.C_FL_CLOSED='N'AND (sub.D_END IS NULL OR sub.D_END>=sysdate) 
        AND sub.C_ACTIVE='Y' AND sub.D_BEGIN<=sysdate
        GROUP BY    sr_goods_pkg_s.GET_NAME_BY_ID(sub.N_SERVICE_ID), 
            si_ref_pkg_s.GET_NAME_BY_ID(gv.N_REF_ID),
            si_ref_pkg_s.GET_NAME_BY_ID(
                SI_SUBJECTS_PKG_S.GET_SUBJ_TYPE_ID(
                    SI_SUBJECTS_PKG_S.GET_BASE_SUBJECT_ID(sub.N_SUBJECT_ID)))
        ORDER BY sr_goods_pkg_s.GET_NAME_BY_ID(sub.N_SERVICE_ID), 
        si_ref_pkg_s.GET_NAME_BY_ID(
            SI_SUBJECTS_PKG_S.GET_SUBJ_TYPE_ID(
            SI_SUBJECTS_PKG_S.GET_BASE_SUBJECT_ID(sub.N_SUBJECT_ID))),
                si_ref_pkg_s.GET_NAME_BY_ID(gv.N_REF_ID)
                """
        return await self.query_names(sql)
 
    @check_connection
    async def query(self, sql: str, args=None, one: bool = False, update: bool = False):
        """
        Делаем произвольный запрос к бд. Возвращаем полученные данные
        :param sql: текст запроса
        :param args: параметры запроса
        :param one: True - выдавать одну запись. False (идет по умолчанию) -  все
        :param update: Нужно ли делать коммит после выполнения запроса. По умолчанию False
        :return: Полученные из бд данные
        """
        if args is None:
            await self.execute_async(self.cursor.execute, sql)
        else:
            await self.execute_async(self.cursor.execute, sql, args)
        if update:
            await self.commit()
            return self.cursor.rowcount
        if one:
            return await self.execute_async(self.cursor.fetchone)
        else:
            return await self.execute_async(self.cursor.fetchall)
 
    @check_connection
    async def query_names(self, sql: str, args=None, one: bool = False, update: bool = False):
        """
        Делаем произвольный запрос к бд. Возвращаем полученные данные.
        Данные возвращаются в виде списка словарей, ключ в которых - наименование колонки из
        sql запроса.
        :param sql: текст запроса
        :param args: параметры запроса
        :param one: True - выдавать одну запись. False (идет по умолчанию) -  все
        :param update: Нужно ли делать коммит после выполнения запроса. По умолчанию False
        :return: Полученные из бд данные
        """
        if args is None:
            await self.execute_async(self.cursor.execute, sql)
        else:
            await self.execute_async(self.cursor.execute, sql, args)
        if update:
            await self.commit()
            return self.cursor.rowcount
        if one:
            return [dict((self.cursor.description[idx][0], value)
                         for idx, value in enumerate(await self.execute_async(self.cursor.fetchone)))]
        else:
            return [dict((self.cursor.description[idx][0], value)
                         for idx, value in enumerate(row))
                    for row in await self.execute_async(self.cursor.fetchall)]
Пример использования
0
 Аватар для Wi0M
395 / 123 / 48
Регистрация: 26.10.2013
Сообщений: 734
25.02.2017, 03:08
alex925, вы решили мою нишу по написанию извратов занять?
Кликните здесь для просмотра всего текста

Python
1
2
3
4
5
6
7
8
9
10
11
12
def my_dec(func):
    def wrapper(*arg, **kw):
        return func(*arg, **kw)
    return wrapper
 
 
@my_dec
def some_func(my_var):
    print(my_var)
 
some_func('hello')
some_func(my_var='hello')


Добавлено через 4 минуты
Zuzik, круто с классом получалось) а переменную в функцию передать не получилось
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
25.02.2017, 06:12
Python
1
raise Exception('Параметры cursor и connection не должны указываться')
Тогда зачем эти параметры в __init__?
0
 Аватар для Zuzik
298 / 256 / 57
Регистрация: 11.06.2012
Сообщений: 1,557
25.02.2017, 13:18  [ТС]
0x10, впринципе незачем. Добавил для удобства разработки. В конструкторе тип данных переменных указан, IDE этот тип видит и обеспечивает автодополнение. По факту - нужно убрать, ибо это лишние действия не несущие существенной пользы.

Wi0M, читаем мое первое сообщение внимательно. Мне хотелось, чтобы переменная извне в функцию передавалась, в ней была доступна для использования, но эту переменную в составе параметров функции передавать не было нужно. Сейчас уже вариант с классом подходит чуть больше, он решил еще пару сопутствующих вопросов.
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
25.02.2017, 13:26
Цитата Сообщение от Zuzik Посмотреть сообщение
В конструкторе тип данных переменных указан, IDE этот тип видит и обеспечивает автодополнение.
PEP 526: Syntax for variable annotations

Если недоступен Python 3.6, можно написать комментарий, IDE подхватит.
1
Заблокирован
25.02.2017, 14:54
А зачем вообще использовать декораторы, ведь это не более чем убогая обертка над лямбдой.
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
25.02.2017, 15:32
actionpattern, ты прикалываешься? Вот расскажи, что такое по твоему декоратор?
0
 Аватар для Wi0M
395 / 123 / 48
Регистрация: 26.10.2013
Сообщений: 734
25.02.2017, 15:34
actionpattern, над какой еще лямбдой?
Zuzik, а... не увидел...
0
Заблокирован
25.02.2017, 16:13
alex925, Wi0M, не надо лапшу на уши вешать

https://pythonworld.ru/osnovy/dekoratory.html
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
25.02.2017, 16:16
Лапшу на уши вешаешь это ты.
0
Заблокирован
25.02.2017, 16:18
alex925, я что-то не так сказал? Обоснуйте.
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
25.02.2017, 16:30
Декораторы это синтаксический сахар для того, чтобы добавить какую-то логику (функции, классу), а lambda это однострочная функция, которая чаще всего используется, чтобы отсрочить вызов чего-то.
0
 Аватар для Wi0M
395 / 123 / 48
Регистрация: 26.10.2013
Сообщений: 734
25.02.2017, 18:11
actionpattern, будьте тактичны и конкретны в своих высказываниях. ибо не понятно о чем вы вообще говорите, какие то обертки над лямбдой... чушь... учите мат часть.
Декоратор всегда возвращающий результат первого вызова метода.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def decorator(fun):
    decorator._store_var = None
    def wrapper(*args, **kwargs):
        if decorator._store_var is None:
            decorator._store_var = fun(*args, **kwargs)
        return decorator._store_var
    return wrapper
 
 
@decorator
def foo(var):
    return var
 
 
print(foo('1'))
print(foo('2'))
Также пишется декоратор для замера времени выполнения метода. Вообще декораторы нужны для того чтобы выполнить что то до вызова метода и после него, без изменения основного метода.
Кстати, есть серия статей на хабре, гуглите "понимаем декораторы". И пожалуйста не говорите что то конкретное о вещах которых вы не знаете или не понимаете...

Добавлено через 18 минут
вот даже ссылка что вы дали, четко написано "Декораторы — это, по сути, "обёртки", которые дают нам возможность изменить поведение функции, не изменяя её код." нет никакой речи о лямбда функциях.
0
Заблокирован
25.02.2017, 18:26
Цитата Сообщение от Wi0M Посмотреть сообщение
Вообще декораторы нужны для того чтобы выполнить что то до вызова метода и после него, без изменения основного метода.
так я об этом и говорил. просто обертка над лямбдой

Добавлено через 2 минуты
Цитата Сообщение от Wi0M Посмотреть сообщение
нет никакой речи о лямбда функциях
это в пистоне путаница, потому что там для лямбд тоже костыльный синтаксис, поэтому возникают терминологические недоразумения. По-сути, лямбда и есть обычная функция.
0
 Аватар для Wi0M
395 / 123 / 48
Регистрация: 26.10.2013
Сообщений: 734
25.02.2017, 18:27
actionpattern, да что ж такое то.
лямбда это
Python
1
x = lambda x: x
да я не спорю что можно ее и в декоратор обернуть, но так никто не делает) потому что это полный бред. мы гооврим про декораторы, а декорируют методы (декораторы методов), другие декораторы (декораторы декораторов для передачи параметра в декоратор) и классы (декораторы классов)
0
Заблокирован
25.02.2017, 18:29
Wi0M, короче, все я правильно сказал. Пистонщики понимают пистон хуже тех, кто его вообще не знает, забавно
0
25.02.2017, 18:31

Не по теме:

ой все

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
25.02.2017, 18:31
Помогаю со студенческими работами здесь

Нужно реализовать задачу с использованием итераторов и декораторов
Помогите пожалуйста, реализовать задачу с использованием итераторов и декораторов. from random import randint # Создание списка,...

Реализация декораторов вне зависимости от количества аргументов и их имен
Доброго времени. У меня есть код с декораторами def bold(x): def wrapped(): return &quot;&lt;b&gt;&quot; + x() +...

Задача "Генератор декораторов"
Напишите генератор декораторов check_password, т. е. функцию, которая возвращает декоратор. Генератор декораторов принимает в качестве...

Разработка, отладка и испытание программ с применением декораторов свойств классов
Продемонстрируйте работу декоратора через задание свойств объекта класса конструктором, сеттером и непосредстсвенным изменением значения...

С помощью декораторов устранить уязвимость Фродо к Назгулам и оку Саурона.
Люди добрые, прошу помочь с решение задачи на декораторы... Мерри и Пиппин, утащившие палантир у Сарумана с ужасом обнаружили, что...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути
Programma_Boinc 01.01.2026
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути Сочетание глобально распределённой вычислительной мощности и инновационных. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru