python装饰器实例-实例方法上的Python装饰器

1586010002-jmsa.png

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值