Python 类装饰器中如何使用 functools.wraps 保留原函数的属性?

2019-08-12 16:28:24 +08:00
 wuwukai007
1966 次点击
所在节点    Python
15 条回复
wuwukai007
2019-08-12 16:29:11 +08:00
class check_token(RefreshJSONWebTokenSerializer,VerifyJSONWebTokenSerializer):
func = None

def __init__(self,fun,*args,**kwargs):
self.func = fun

@functools.wraps(func)
def __call__(self,request,*args, **kwargs):
try:
token = request.COOKIES.get('token')
payload =self. _check_payload(token=token)
user = self._check_user(payload=payload)
wuwukai007
2019-08-12 16:29:33 +08:00
使用这种曲线那 fun 的方式,还是不行
myyou
2019-08-12 16:33:54 +08:00
class check_token(RefreshJSONWebTokenSerializer,VerifyJSONWebTokenSerializer):

def __init__(self,fun,*args,**kwargs):
pass

def __call__(self, func):
@wraps(func)
def wrapped_function(request, *args, **kwargs):
token = request.COOKIES.get('token')
payload =self. _check_payload(token=token)
user = self._check_user(payload=payload)
return func(request, *args, **kwargs)
return wrapped_function
wuwukai007
2019-08-12 16:37:38 +08:00
@myyou 我试一下,主要是用类装饰器后,函数中如果用 super 方法,拿到的是类装饰器中的 super
wuwukai007
2019-08-12 16:41:18 +08:00
class check_token(generics.ListCreateAPIView,):
queryset = models.Report.objects.all()
serializer_class = Report_Serializer
authentication_classes = []
@check_token
def post(self,request,*args,**kwargs):
return Response({'content':'111'},status=200)

@check_token
def list(self, request, *args, **kwargs):
resp = super(generics.ListCreateAPIView,self).list(request,*args,**kwargs)
return resp


用了上面的类装饰器,我的 list 函数调用 ListCreateAPIVie 中的 list 中 super 方法,拿到的是装饰器中继承的类,而不是 ListCreateAPIVie 中的 list
myyou
2019-08-12 16:49:38 +08:00
你是不是把 def __call__(self, func):这里的 self 传给了 func 函数,导致了 func 的 self 函数被替换?
wuwukai007
2019-08-12 16:55:56 +08:00
@myyou 在__call__中使用闭包,可以用 functools 装饰,但是还是拿不到本身的类
myyou
2019-08-12 17:01:05 +08:00
class check_token(RefreshJSONWebTokenSerializer,VerifyJSONWebTokenSerializer):

def __call__(self, func):
@wraps(func)
def wrapped_function(func_self, request, *args, **kwargs):
token = request.COOKIES.get('token')
payload =self. _check_payload(token=token)
user = self._check_user(payload=payload)
return func(func_self, request, *args, **kwargs)
return wrapped_function

类按这样写
装饰器写成 @check_token() 加括号试试
wuwukai007
2019-08-12 17:02:50 +08:00
@myyou 加了,里面随便放了参数,self 关键字我也改了,不行爱
wuwukai007
2019-08-12 17:03:40 +08:00
def __call__(self,func):
print(self,func)
@functools.wraps(func)
def hander(selff,request,*args,**kwargs):
print(selff)
try:
token = request.COOKIES.get('token')
payload =selff. _check_payload(token=token)
user = selff._check_user(payload=payload)
except Exception as e:
# r = Response({'code': 400, 'message': e.detail[0]})
r = Response({'code': 400, 'message': str(e)})
# r.set_cookie('token','111')
return r
else:
resp = func(selff, request, *args, **kwargs)
try:
new_token = selff.validate({'token':token})
except Exception as e:
return Response({'code':'令牌更新错误'})
else:
resp.set_cookie('token',new_token['token'])
return resp
return hander



@check_token('1')
def list(self, request, *args, **kwargs):
resp = super(generics.ListCreateAPIView,self).list(request,*args,**kwargs)
return resp
wuwukai007
2019-08-12 17:10:02 +08:00
现在是可以拿到了本身的函数,但是本身函数继承的类中的方法拿不到,报没有方法等
myyou
2019-08-12 17:11:06 +08:00
resp = super(generics.ListCreateAPIView,self).list(request,*args,**kwargs)
改称 super().list(request,*args,**kwargs)
myyou
2019-08-12 17:14:44 +08:00
super()方法会使用类的 mro 表第二个类的实例,所以用 super 的时候要注意一点
wuwukai007
2019-08-12 18:24:02 +08:00
@myyou 我傻 b 了,我的 hander 里面用 self 关键字,调用装饰器中继承的方法,func 中用 selff,使用本身的实例就好了 多谢!
http://www.chaoyue.red/static/media/1565602027(1).jpg
留言被限制半小时…
vkhsyj
2019-08-12 22:31:07 +08:00
update_wrapper,进源码看一下 wraps 怎么实现的就知道怎么做了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/591226

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX