task_summary — это метод контроллера, который обрабатывает HTTP запрос.
Фреймворк не важен, наш собственный.
Есть необходимость проверять права доступа в декораторе @access; право доступа к сущности условно
определяются тройкой UID, SID, ACTION.
В access мы передаем класс и action, UID он может взять из http сессии, экшн мы передаем,
а вот как туда втащить SID? SID — это идентификатор ресурса, доступ к которому проверяется, он зависит от контекста.
В данном примере — это параметр GET-запроса id, который передается функции контроллера, но может быть и не так.
Хочется его как-то декларативно описать, откуда декоратору @access брать этот самый SID.
Попытались это сделать путем описания внутренней функции SID(), но она недоступна извне без хака (интроспекции),
да и не функция это должна быть, а замыкание по-сути.
В общем, хочется описать это 1) декларативно, 2) — в контексте функции-обработчика, т.е. не плодить какого-то кода,
специфичного для данного контекста вне этого контекста. Как — вот вопрос.
Как, допустим, добавить атрибут этой функции изнутри нее?
12.12.08 20:36: Перенесено модератором из 'Декларативное программирование' — Кодт
.>>Может можно на keywords перейти.
dmz>Понятно, но это не помогает, так как id — контекстно зависимый. dmz>Может поступить как параметр, может быть получен в результате lookup или еще как.
dmz>В общем сделал пока тупо, но сомнения остались.
Могу предложить еще одно не очень красивое решение. Превратить task_summary в генератор, и тогда будет возможность приостанавливать ход работы функции и получать промежуточные результаты в декораторе:
dmz wrote:
> .>Может можно на keywords перейти. > Понятно, но это не помогает, так как id — контекстно зависимый. > Может поступить как параметр, может быть получен в результате lookup или > еще как. > > В общем сделал пока тупо, но сомнения остались.
Может тогда плюнуть на все эти @-прибамбасы и писать в стиле ООП с классами?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
dmz wrote: > Понятно, но это не помогает, так как id — контекстно зависимый. > Может поступить как параметр, может быть получен в результате lookup или > еще как. > > В общем сделал пока тупо, но сомнения остались.
Можно вот так, попроще:
В общем, ничего хорошего не придумалось, а тем временем появилось
уже два места, где мне требуется похожий функционал.
Попробую формализовать задачу:
Есть некоторый метод, который вызывается по некоторому событию (обрабатывает HTTP запрос,
если это имеет значение). Есть набор декораторов, которые добавляют стандартное поведение:
сформировать и выплюнуть xml для набора объектов, которые этот метод возвращает, наложить на него
xsl и отдать в middleware ( декоратор render), проверить права доступа — декоратор access,
закэшировать — декоратор cache.
декоратор render пока обходится без контекста — ему достаточно того, что ему передают.
декораторы access и cache — требуют некоторые идентификаторы, которые, вообще говоря, динамические и
зависят от контекста: пример — если мы кэшируем запрос, то ключом является какая-то производная от параметров GET запроса и состояния сессии — что конкретно, и как с этим работать — знает сам метод handle_some_request.
Вопрос все-тот же: как это знание обособить, причем строго внутри метода-обработчика и довести до сведения декоратора.
хочется как-то использовать внутренние функции — потому что они видят параметры, передаваемые методу, но их нельзя
выполнить вне функций, внутри которых они объявлены. Хочется при этом минимально менять логику обработчиков запросов — их весьма много, и это будет уже нетривиальная вещь, которую придется описывать, доводить до сведения разработчиков и т.п.
Чо делать? В принципе, я согласен написать какой-то достаточно злобный __new__, который будет путем интроспекции смотреть, нет ли внутри обработчиков запросов внутренних функций, делать из них лямбды, запоминать их и вызывать в нужном контексте — но не очень представляю, как это сделать, и мучит подозрение, что можно сделать как-то более красиво.
Давайте вместе подумаем — по-моему, будет прикольная тема, если получится.
Re[5]: [Python] продолжение банкета
От:
Аноним
Дата:
14.07.07 21:30
Оценка:
dmz>декораторы access и cache — требуют некоторые идентификаторы, которые, вообще говоря, динамические и dmz>зависят от контекста: пример — если мы кэшируем запрос, то ключом является какая-то производная от параметров GET запроса и состояния сессии — что конкретно, и как с этим работать — знает сам метод handle_some_request.
dmz>Вопрос все-тот же: как это знание обособить, причем строго внутри метода-обработчика и довести до сведения декоратора. dmz>хочется как-то использовать внутренние функции — потому что они видят параметры, передаваемые методу, но их нельзя dmz>выполнить вне функций, внутри которых они объявлены. Хочется при этом минимально менять логику обработчиков запросов — их весьма много, и это будет уже нетривиальная вещь, которую придется описывать, доводить до сведения разработчиков и т.п.
dmz>Чо делать? В принципе, я согласен написать какой-то достаточно злобный __new__, который будет путем интроспекции смотреть, нет ли внутри обработчиков запросов внутренних функций, делать из них лямбды, запоминать их и вызывать в нужном контексте — но не очень представляю, как это сделать, и мучит подозрение, что можно сделать как-то более красиво.
А если поступить ровно наоборот?
Передавать из декоратора колбэк, получит значение контекстной переменной?
Примерно так:
Ну а кроме того, можно лямбду загнать в параметры по умолчанию, а потом её добыть.
Можно в самой функции установить себе атрибут и его из обвязки получить после первого прогона, который можно и искуственно сделать.
Ещё можно её как текст в док-стринг запихать... Но это уже совсем изврат.
dmz wrote:
> В общем, ничего хорошего не придумалось, а тем временем появилось > уже два места, где мне требуется похожий функционал.
Я тебе столько вариантов привёл, ты скажи чем не устраивает?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
dmz wrote:
> Блин, как бы просто решался вопрос, если бы можно было вызвать вложенную > функцию из декоратора
Всё вложенное — это дело функции, пока сама не отдаст — никто не может отобрать.
> , или при описании функции выставить у нее атрибут.
Атрибут у функции это как? Ведь функция существует глобально. Нереентерабельно и потоко-небезопасно получится.
> Почему этого никак не сделать...
По-моему тоже. Хотя я питон не знаю, учебник только полистал однажды.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
>> , или при описании функции выставить у нее атрибут. .>Атрибут у функции это как? Ведь функция существует глобально. Нереентерабельно и потоко-небезопасно получится.
Ну и что? Функция — это такой же объект, как все остальное. Соответственно, всегда можно сделать вот так вот:
Еще вариант, сделать второй декоратор, который будет анализировать не отдекорирована ли уже фнукиция первым декоратором, связываться с ним и объяснять ему откуда взять sid
или наоборот
@sid(fromParameter = 'SID')
@access(Task_Permission, "view_summary", SID)
dmz wrote:
> .>Атрибут у функции это как? Ведь функция существует глобально. > Нереентерабельно и потоко-небезопасно получится. > > Ну и что? Функция — это такой же объект, как все остальное. > Соответственно, всегда можно сделать вот так вот:
Я имею в виду, что вот ты для неё установил из декоратора 42, а потом во время работы этой функции кто-нибудь другой эту
же функцию вызвал и декоратор установил в 38, то 42 просто затрётся, и функция продолжит работать с неверным значением.
Значение получается глобальным, не зависящим от контекста, стека.
> TurboGears, в частности, так делает.
Что именно делает?.. (я никогда не юзал его)
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
.>же функцию вызвал и декоратор установил в 38, то 42 просто затрётся, и функция продолжит работать с неверным значением.
Угу. С другой стороны, в этот атрибут можно было бы засунуть саму функцию вычисления SID,
а вот параметры передавать ей из контекста — он-то декоратору известен.
dmz wrote:
> .>же функцию вызвал и декоратор установил в 38, то 42 просто затрётся, и > функция продолжит работать с неверным значением. > > Угу. С другой стороны, в этот атрибут можно было бы засунуть саму > функцию вычисления SID, > а вот параметры передавать ей из контекста — он-то декоратору известен.
Функцию-шмункцию... какая разница? Разве можно гарантировать, что каждый раз будет подсовываться одна и та же функция?
Так что с идеологической т.з., с т.з. дизайна языка это паршиво, декораторы не хак таки, чтобы херачить что угодно, а
типа АОП прибамбас.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, dmz, Вы писали:
dmz>Хочется его как-то декларативно описать, откуда декоратору @access брать этот самый SID. dmz>Попытались это сделать путем описания внутренней функции SID(), но она недоступна извне без хака (интроспекции)
Внутрення функкция создается динамически в момент вызова task_summary. Тут тебе никакая интроспекция не поможет. Чтобы получить нормальный SID нужно по-честному вызвать внешнюю функцию. Без вариантов.
dmz>да и не функция это должна быть, а замыкание по-сути.
Ну так и возвращай замыкание (кортеж из двух функций)!
def test(self, id):
def SID():
return id
return SID, lambda: self._task_summary_inner(id)
# вызов
sid, f = obj.test(id)
if sid() == 42:
f()
dmz>В общем, хочется описать это 1) декларативно, 2) — в контексте функции-обработчика, т.е. не плодить какого-то кода, dmz>специфичного для данного контекста вне этого контекста. Как — вот вопрос.
Вообще, советую обдумать идею просто вставить assert, как уже выше предалагалось.
Ислючения в питоне бросаются и ловятся достаточно эффективно
.>>Может можно на keywords перейти.
dmz>Понятно, но это не помогает, так как id — контекстно зависимый. dmz>Может поступить как параметр, может быть получен в результате lookup или еще как.
dmz>В общем сделал пока тупо, но сомнения остались.
Вопрос уже неактуален скорее всего ... но давно не было тем про python
Можно описывать функцию получения id в комментарии метода
@render('task-summary.xsl', debug=True, cache=False)
@access(Task_Permission, "view_summary")
def task_summary(self, id):
"""
uid:
return id
"""
return "the summary ..."