Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python装饰器和类继承_Python_Web Applications_Decorator_Subclassing - Fatal编程技术网

Python装饰器和类继承

Python装饰器和类继承,python,web-applications,decorator,subclassing,Python,Web Applications,Decorator,Subclassing,我试图使用decorator来管理用户访问web应用程序(在Google App Engine上运行)中资源的方式。请注意,我不允许用户使用他们的Google帐户登录,因此在app.yaml中设置特定路线的特定访问权限不是一个选项 我使用了以下资源: - - - - 但是我还是有点困惑 这是我的密码!在下面的示例中,当前_用户是属于RequestHandler类的@property方法。它返回存储在数据存储中的用户(db.model)对象,其级别为IntProperty() 但是,我的应用程序对

我试图使用decorator来管理用户访问web应用程序(在Google App Engine上运行)中资源的方式。请注意,我不允许用户使用他们的Google帐户登录,因此在app.yaml中设置特定路线的特定访问权限不是一个选项

我使用了以下资源:
-
-
-
-

但是我还是有点困惑

这是我的密码!在下面的示例中,当前_用户是属于RequestHandler类的@property方法。它返回存储在数据存储中的用户(db.model)对象,其级别为IntProperty()

但是,我的应用程序对不同类型的资源使用不同的控制器。为了在所有子类中使用@requiredLevel装饰器,我需要将其移动到父类(RequestHandler):

我的想法是使用以下代码访问所有控制器子类中的装饰器:

class FoobarController(RequestHandler):

    @RequestHandler.requiredLevel(100)
    def get(self):
        #do stuff here...

我想我对装饰器和类继承的知识已经达到了极限:)。有什么想法吗?

在仔细阅读StackOverflow之后,我想我找到了一个可能的解决方案

它涉及将装饰器作为父类中的一个类来实现:

class RequestHandler(webapp.RequestHandler):

    # Decorator class :
    class requiredLevel(object):
        def __init__(self, required_level):
            self.required_level = required_level

        def __call__(self, f):
            def wrapped_f(*f_args):
                if f_args[0].current_user.level >= self.required_level:
                    return f(*f_args)
                else:
                    raise Exception('User has insufficient level to access this resource') 
            return wrapped_f
这就行了!使用f_args[0]对我来说似乎有点脏,如果我找到更漂亮的答案,我会编辑这个答案

然后可以通过以下方式在子类中修饰方法:

FooController(RequestHandler):
    @RequestHandler.requiredLevel(100)
    def get(self, id):
        # Do something here

    @RequestHandler.requiredLevel(250)
    def post(self)
        # Do some stuff here

BarController(RequestHandler):
    @RequestHandler.requiredLevel(500)
    def get(self, id):
        # Do something here

请随意评论或提出增强。

您的原始代码,加上两个小改动,也应该可以工作。对于这样一个简单的装饰器,基于类的方法似乎相当重要:

class RequestHandler(webapp.RequestHandler):

    # The decorator is now a class method.
    @classmethod     # Note the 'klass' argument, similar to 'self' on an instance method
    def requiredLevel(klass, required_level):
        def wrap(func):
            def f(self, *args):
                if self.current_user.level >= required_level:
                    func(self, *args)
                else:
                    raise Exception('Insufficient level to access this resource') 
            return f
        return wrap


class FoobarController(RequestHandler):
    @RequestHandler.requiredLevel(100)
    def get(self, someparameters):
        #do stuff here...

    @RequestHandler.requiredLevel(200)
    def post(self):
        #do something else here...
或者,您可以使用
@staticmethod

class RequestHandler(webapp.RequestHandler):

    # The decorator is now a static method.
    @staticmethod     # No default argument required...
    def requiredLevel(required_level):
原始代码不起作用的原因是假定requiredLevel是一个实例方法,它在类声明时不可用(当您装饰其他方法时),在类对象中也不可用(将decorator放在RequestHandler基类上是一个很好的主意,并且生成的decorator调用可以很好地自文档化)

您可能有兴趣阅读和的文档

另外,我喜欢在我的装饰师身上放一点样板:

    @staticmethod
    def requiredLevel(required_level):
        def wrap(func):
            def f(self, *args):
                if self.current_user.level >= required_level:
                    func(self, *args)
                else:
                    raise Exception('Insufficient level to access this resource') 
            # This will maintain the function name and documentation of the wrapped function.
            # Very helpful when debugging or checking the docs from the python shell:
            wrap.__doc__ = f.__doc__
            wrap.__name__ = f.__name__
            return f
        return wrap

为什么它是类上的一个方法?这只会导致问题的解决,而且它只能像它定义的类中的一个常规函数一样工作。除非你是在3.x上,在这种情况下,它可能会正常工作。decorator是类上的一个方法,因为我还没有弄清楚如何将decorator编码为类1/并接受参数2/这可以访问当前类本身的方法。这就是你的意思吗?由于大部分是自学的,我很难完全理解Bruce Eckell的指南、装饰器和继承。你只需将函数复制粘贴到类外,它就会正常工作。这足以回答你的问题吗?移动requiredLevel decorator从FoobarController到RequestHandler,并使用@staticmethod对其进行修饰似乎是解决方案,但在我的情况下,它不起作用。很可能是因为我的decorator接受参数?不,我的意思是将其从类中完全删除。使其成为常规函数。您可以使用
wrapped\u f(request_handler,*args,**kwargs)
作为函数签名。也没有必要将decorator类放入RequestHandler类中。我将把它放在模块级。谢谢你的评论!我想你刚刚让我了解了继承的工作方式不同(而且更好)。我将相应地更新我的代码。
class RequestHandler(webapp.RequestHandler):

    # The decorator is now a static method.
    @staticmethod     # No default argument required...
    def requiredLevel(required_level):
    @staticmethod
    def requiredLevel(required_level):
        def wrap(func):
            def f(self, *args):
                if self.current_user.level >= required_level:
                    func(self, *args)
                else:
                    raise Exception('Insufficient level to access this resource') 
            # This will maintain the function name and documentation of the wrapped function.
            # Very helpful when debugging or checking the docs from the python shell:
            wrap.__doc__ = f.__doc__
            wrap.__name__ = f.__name__
            return f
        return wrap