我有一个类似下面的龙卷风方法,我试图装饰方法来缓存东西。我有以下设置
def request_cacher(x):
def wrapper(funca):
@functools.wraps(funca)
@asynchronous
@coroutine
def wrapped_f(self, *args, **kwargs):
pass
return wrapped_f
return wrapper
class PhotoListHandler(BaseHandler):
@request_cacher
@auth_required
@asynchronous
@coroutine
def get(self):
pass
我收到错误AttributeError: 'PhotoListHandler' object has no attribute '__name__'
有什么想法吗?
答案 0 :(得分:3)
问题是您将request_cacher
装饰器定义为带参数的装饰器,但您忘记传递参数!
考虑以下代码:
import functools
def my_decorator_with_argument(useless_and_wrong):
def wrapper(func):
@functools.wraps(func)
def wrapped(self):
print('wrapped!')
return wrapped
return wrapper
class MyClass(object):
@my_decorator_with_argument
def method(self):
print('method')
@my_decorator_with_argument(None)
def method2(self):
print('method2')
当您尝试在实例中使用method
时,您会得到:
>>> inst = MyClass()
>>> inst.method # should be the wrapped function, not wrapper!
<bound method MyClass.wrapper of <bad_decorator.MyClass object at 0x7fed32dc6f50>>
>>> inst.method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "bad_decorator.py", line 6, in wrapper
@functools.wraps(func)
File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'MyClass' object has no attribute '__name__'
正确使用装饰器:
>>> inst.method2()
wrapped!
替代修复方法是从装饰器中删除一个图层:
def my_simpler_decorator(func):
@functools.wraps(func)
def wrapped(self):
print('wrapped!')
return wrapped
class MyClass(object):
@my_simpler_decorator
def method3(self):
print('method3')
你可以看到它没有引起错误:
>>> inst = MyClass()
>>> inst.method3()
wrapped!
答案 1 :(得分:0)
我认为这可能适合你,
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine
from functools import wraps
cache = {}
class cached(object):
def __init__ (self, rule, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.rule = rule
cache[rule] = 'xxx'
def __call__(self, fn):
def newf(*args, **kwargs):
slf = args[0]
if cache.get(self.rule):
slf.write(cache.get(self.rule))
return
return fn(*args, **kwargs)
return newf
class MainHandler(tornado.web.RequestHandler):
@coroutine
@cached('/foo')
def get(self):
print "helloo"
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
答案 2 :(得分:0)
您的代码会从functools.wraps(funca)
引发,因此funca
必须是PhotoListHandler
实例,而不是您想要的包裹get
方法。我相信这意味着堆栈中的下一个装饰器auth_required
被错误地写入:auth_required
正在返回self
而不是返回一个函数。
虽然我在这里:在经过身份验证的功能之上堆叠缓存对我来说是错误的。赢得第一个经过身份验证的用户的照片列表是否会被缓存,然后显示给所有后续用户?