2016-08-02 38 views
0

Ich habe eine Tornado-Methode wie unten und ich habe versucht, Methode zu cachen Zeug zu dekorieren. Ich habe folgendes SetupPython Decorators - <Classname> Objekt hat kein Attribut '__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 

ich den Fehler erhalte, AttributeError: 'PhotoListHandler' object has no attribute '__name__' Irgendwelche Ideen?

+0

Sie erkennen, dass Sie die '@ asynchronous' anwenden und' @ coroutine' Dekorateure zweimal? – holdenweb

+0

ja, das tue ich. dieser Cache aufrufbar muss auch asynchron arbeiten – tunaktunak

+0

Bitte buchen Sie die vollständige Traceback, nicht nur die Ausnahme. –

Antwort

0

Ich denke, das für Sie arbeitet,

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

Ihr Code aus functools.wraps(funca) wirft, so funca muss eine PhotoListHandler Instanz anstelle einer umhüllten get Methode, wie Sie mögen. Ich glaube, das bedeutet, dass der nächste Dekorierer im Stapel auth_required falsch geschrieben ist: auth_required gibt self zurück, anstatt eine Funktion zurückzugeben.

Während ich hier bin: das Stapeln eines Cache über einer authentifizierten Funktion sieht für mich falsch aus. Wird die Fotoliste des ersten authentifizierten Benutzers nicht im Cache gespeichert und dann allen nachfolgenden Benutzern angezeigt?

+0

dasselbe Ergebnis, wenn ich auskommen auth erforderlich – tunaktunak

3

Das Problem ist, dass Sie Ihren request_cacher Dekorateur als Dekorator mit Argumenten definiert haben, aber Sie haben vergessen, das Argument zu übergeben!

Betrachten Sie diesen Code:

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') 

Wenn Sie versuchen, method in einer Instanz zu verwenden, erhalten Sie:

>>> 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__' 

Mit der korrekten Verwendung des Dekorateur:

>>> inst.method2() 
wrapped! 

Alternative Fix ist eine Schicht vom Dekorateur entfernen:

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') 

Und man kann sehen, dass es den Fehler nicht erhöhen:

>>> inst = MyClass() 
>>> inst.method3() 
wrapped!