将函数传递给类并将其用作类方法的装饰器

时间:2017-12-15 21:21:41

标签: python class cherrypy python-decorators

首先,我创建了一些我想在任何地方使用的用户管理功能,并将它们绑定到樱桃,认为我可以在其他地方导入cherrypy,他们会在那里。当不用作装饰器时,其他函数似乎以这种方式导入。

from user import validuser
cherrypy.validuser = validuser
del validuser

这不起作用,所以接下来我尝试将该函数传递到我的cherrypy网站(/analyze)的一个类中,从顶级类页面开始:

class Root:
    analyze = Analyze(cherrypy.validuser) #maps to /analyze

在Analyze课程中,我提到了他们。这适用于普通函数,但不适用于装饰器。为什么不呢?

class Analyze:

    def __init__(self, validuser):
        self.validuser = validuser

    @cherrypy.expose
    @self.validuser(['uid'])
    def index(self, **kw):        
        return analysis_panel.pick_data_sets(user_id=kw['uid'])

我被困住了。我如何传递函数并将它们用作装饰器。我宁愿不像这样包装我的函数:

    return self.validuser(analysis_panel.pick_data_sets(user_id=kw['uid']),['uid'])

感谢。

ADDED / EDITED:这是装饰者正在做的事情,因为作为一个单独的问题,我认为它没有正确地将user_id添加到kwargs中

def validuser(old_function, fetch=['uid']):
    def new_function(*args, **kw):
        "... do stuff. decide is USER is logged in. return USER id or -1 ..."
        if USER != -1 and 'uid' in fetch:
            kw['uid'] = user_data['fc_uid']
        return old_function(*args, **kw)
    return new_function

只有传入的kwargs出现在new_function的kwargs中。我尝试添加的任何东西都不存在。 (我正在做的事情似乎在这里工作How can I pass a variable in a decorator to function's argument in a decorated function?

2 个答案:

答案 0 :(得分:1)

CherryPy处理这种情况的正确方法是拥有a tool并在网站需要身份验证的部分启用该工具。首先考虑创建这个用户身份验证工具:

@cherrypy.tools.register('before_handler')
def validate_user():
    if USER == -1:
        return
    cherrypy.request.uid = user_data['fc_uid']

请注意'register' decorator was added in CherryPy 5.5.0

然后,无论您希望如何验证用户,都可以使用工具修饰处理程序:

class Analyze:

    @cherrypy.expose
    @cherrypy.tools.validate_user()
    def index(self):
        return analysis_panel.pick_data_sets(user_id=cherrypy.request.uid)

或者在您的cherrypy配置中,启用该工具:

config = {
    '/analyze': {
        'tools.validate_user.on': True,
    },
}

答案 1 :(得分:0)

函数/方法是在类中定义的,用实例变量装饰它是没有意义的,因为它不是每个实例的相同装饰器。

您可以考虑使用property在访问时创建装饰方法:

@property
def index(self):
    @cherrypy.expose
    @self.validuser(['uid'])
    def wrapped_index(**kw):
        return analysis_panel.pick_data_sets(user_id=kw['uid'])
    return wrapped_index

您也可以考虑尝试应用lru_cache为每个实例保存方法,但我不确定如何将该方法应用于该属性。