【问题标题】:passing function into a class and using it as a decorator of class methods将函数传递给类并将其用作类方法的装饰器
【发布时间】:2023-03-05 05:49:01
【问题描述】:

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

from user import validuser
cherrypy.validuser = validuser
del validuser

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

class Root:
    analyze = Analyze(cherrypy.validuser) #maps to /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'])

谢谢。

添加/编辑:这是装饰器正在做的事情,因为作为一个单独的问题,我认为它没有正确地将 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?

【问题讨论】:

标签: python class cherrypy python-decorators


【解决方案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,
    },
}

【讨论】:

  • 谢谢。如我所愿,这使界面保持简单。一个装饰器对我来说读起来更pythonic。我在 python 3.6(生产)和测试版本上运行版本 7、11、13。所以我需要先升级。
  • 我阅读了文档,您不需要使用 register 装饰器就可以在旧版本上进行这项工作。 github.com/cherrypy/CherryPy/issues/1311 -- 像这样分配它:cherrypy.tools.validate_user = Tool('on_start_resource', validate_user)
  • @jason-r-coombs 我发现这在 site.py 主文件中有效,但是当我在另一个文件中站点的不同部分使用这个装饰器时,它在命名空间中,但不是在“工具箱”中找到:@cherrypy.tools.validate_user() AttributeError: 'Toolbox' 对象没有属性 'validate_user'
  • 如果使用装饰器方法,该工具需要在用作装饰器之前被定义/分配......并且之前意味着相对于 Python 读取模块的顺序。您有两个选择:使用 config 方法,该方法将工具的使用推迟到服务器启动或确保在加载任何这些模块之前尽早安装工具。
  • 我确实找到了this module,其文档字符串说明了如何使用cherrypy.config 作为装饰器来配置单个处理程序。
【解决方案2】:

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

您可以考虑在访问时使用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 来保存每个实例的方法,但我不知道如何将其应用于属性。

【讨论】:

    猜你喜欢
    • 2013-03-10
    • 1970-01-01
    • 2017-11-12
    • 2018-08-24
    • 2018-03-23
    • 2017-05-30
    • 2019-01-25
    • 2021-11-15
    相关资源
    最近更新 更多