python装饰器原理wraps(method)(self),实例方法上的Python装饰器

Anyone know what is wrong with this code?

def paginated_instance_method(default_page_size=25):

def wrap(func):

@functools.wraps(func)

def inner(self, page=1, page_size=default_page_size, *args, **kwargs):

objects = func(self=self, *args, **kwargs)

return _paginate(objects, page, page_size)

return inner

return wrap

class Event(object):

...

@paginated_instance_method

def get_attending_users(self, *args, **kwargs):

return User.objects.filter(pk__in=self.attending_list)

I get the following error:

Traceback (most recent call last):

File "", line 1, in

File "/Users/zarathustra/Virtual_Envs/hinge/hinge_services/hinge/api/decorators.py", line 108, in wrap

def inner(self, page=1, page_size=default_page_size, *args, **kwargs):

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/functools.py", line 33, in update_wrapper

setattr(wrapper, attr, getattr(wrapped, attr))

AttributeError: 'Event' object has no attribute '__name__'

The reason why I thought this would work is because, through trial and error, I got the following decorator working like a charm for classmethods:

def paginated_class_method(default_page_size=25):

def wrap(func):

@functools.wraps(func)

def inner(cls, page=1, page_size=default_page_size, *args, **kwargs):

objects = func(cls=cls, *args, **kwargs)

return _paginate(objects, page, page_size)

return inner

return wrap

解决方案

Your decorator has an extra level of indirection which is throwing things off. When you do this:

@paginated_instance_method

def get_attending_users(self, *args, **kwargs):

return User.objects.filter(pk__in=self.attending_list)

You are doing this:

def get_attending_users(self, *args, **kwargs):

return User.objects.filter(pk__in=self.attending_list)

get_attending_users = paginated_instance_method(get_attending_users)

That is what decorators do. Note that paginated_instance_method is called with get_attending_users as its argument. That means that in your decorator, the argument default_page_size is set to the function paginated_instance_method. Your decorator returns the function wrap, so get_attending_users is set to that wrap function.

Then when you then call Event().get_attending_users() it calls wrap(self), where self is your Event instance. wrap is expecting the argument to be a function, and tries to return a new function wrapping that function. But the argument isn't a function, it's an Event object, so functools.wrap fails when trying to wrap it.

I have a hunch that what you're trying to do is this:

@paginated_instance_method()

def get_attending_users(self, *args, **kwargs):

return User.objects.filter(pk__in=self.attending_list)

That is, you want paginated_instance_method to take an argument. But even if you want to use the default value of that argument, you still have to actually call paginated_instance_method. Otherwise you just pass the method as the argument, which is not what paginated_instance_method is expecting.

The reason it "worked" for a classmethod is that a classmethod takes the class as the first argument, and a class (unlike an instance) does have a __name__ attribute. However, I suspect that if you test it further you'll find it's not really doing what you want it to do, as it's still wrapping the class rather than the method.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值