Ваш оригинальный код, с двумя небольшими изменениями, также должен работать.Подход на основе классов кажется довольно тяжелым для такого простого декоратора:
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, как предполагалось, был методом экземпляра, который не будет доступен во время объявления класса (когда вы декорировали другие методы), и при этом он не будет доступен из объекта класса (помещаяОтличная идея - использовать декоратор в базовом классе RequestHandler, и в результате вызов декоратора самодокументируется).
Вам может быть интересно прочитать документацию о @classmethod
и @staticmethod
.
Кроме того, я хотел бы добавить немного шаблонов в свои декораторы:
@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