2016-08-02 71 views
0

我有一個像下面的龍捲風方法,我試圖裝飾方法來緩存的東西。我有以下設置Python裝飾 - <Classname>對象沒有屬性'__name__'

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

你一定要明白,你所申請的'@ asynchronous'和'@ coroutine'裝飾兩次? – holdenweb

+0

是的,我做。這個可調用的緩存也必須異步工作 – tunaktunak

+0

請發佈完整的追溯,而不僅僅是異常。 –

回答

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() 
0

你的代碼functools.wraps(funca)拋出,所以funca必須的,而不是一個包裹get方法PhotoListHandler實例作爲你打算。我相信這意味着堆棧中的下一個裝飾器auth_required寫入不正確:auth_required正在返回self而不是返回函數。

雖然我在這裏:在認證功能頂部堆疊緩存對我來說看起來是錯誤的。第一個經過身份驗證的用戶的照片列表是否會被緩存,然後顯示給所有後續用戶?

+0

同樣的結果當我註釋auth需要 – tunaktunak

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! 
相關問題