有人知道这段代码有什么问题吗?
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)
我收到以下错误:
Traceback (most recent call last):
File "<console>", line 1, in <module>
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__'
我认为这行得通的原因是,通过反复试验,我得到了以下装饰器,就像类方法的魅力一样:
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
解决方法:
您的装饰器具有额外的间接级别,可以间接解决问题.执行此操作时:
@paginated_instance_method
def get_attending_users(self, *args, **kwargs):
return User.objects.filter(pk__in=self.attending_list)
您正在执行此操作:
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)
这就是装饰者所做的.请注意,使用get_attending_users作为参数调用paginated_instance_method.这意味着在您的装饰器中,参数default_page_size设置为函数paginated_instance_method.装饰器返回函数包装,因此将get_attending_users设置为该包装函数.
然后,当您随后调用Event().get_attending_users()时,它将调用wrap(self),其中self是您的Event实例. wrap期望参数是一个函数,并尝试返回一个包装该函数的新函数.但是参数不是函数,而是Event对象,因此functools.wrap尝试包装时会失败.
我有一种直觉,你想做的是这样的:
@paginated_instance_method()
def get_attending_users(self, *args, **kwargs):
return User.objects.filter(pk__in=self.attending_list)
也就是说,您希望paginated_instance_method接受参数.但是,即使您要使用该参数的默认值,也仍然必须实际调用paginated_instance_method.否则,您仅将方法作为参数传递,这不是paginated_instance_method所期望的.
它对类方法“起作用”的原因是,类方法将类作为第一个参数,并且类(与实例不同)确实具有__name__属性.但是,我怀疑如果进一步测试它,您会发现它并没有真正按照您想要的去做,因为它仍然在包装类而不是方法.