首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python Decorators - <Classname>对象没有属性'__name__‘

Python Decorators - <Classname>对象没有属性'__name__‘
EN

Stack Overflow用户
提问于 2016-08-02 19:19:39
回答 3查看 2.2K关注 0票数 0

我有一个类似于下面的龙卷风方法,我试着装饰方法来缓存东西。我有以下设置

代码语言:javascript
复制
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__'有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-02 20:40:56

我想这可能对你有用,

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2016-08-02 21:20:05

问题是,您将request_cacher装饰器定义为带参数的装饰器,但是忘记了传递参数!

考虑下面的代码:

代码语言:javascript
复制
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时,你会得到:

代码语言:javascript
复制
>>> 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__'

正确使用装饰器:

代码语言:javascript
复制
>>> inst.method2()
wrapped!

另一种解决方法是从装饰器中删除一层:

代码语言:javascript
复制
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')

您可以看到,它不会引发错误:

代码语言:javascript
复制
>>> inst = MyClass()
>>> inst.method3()
wrapped!
票数 5
EN

Stack Overflow用户

发布于 2016-08-02 20:45:00

您的代码是从functools.wraps(funca)抛出的,因此funca必须是一个PhotoListHandler实例,而不是您想要的包装好的get方法。我认为这意味着堆栈下的下一个装饰器auth_required编写错误:auth_required返回self,而不是返回函数。

在这里:在经过身份验证的函数上堆叠缓存在我看来是错误的。第一个通过身份验证的用户的照片列表不会被缓存,然后显示给所有后续用户吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38719002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档