首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
宝塔
V2EX  ›  Python

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

  •  
  •   wuwukai007 · 102 天前 · 857 次点击
    这是一个创建于 102 天前的主题,其中的信息可能已经有所发展或是发生改变。
    15 回复  |  直到 2019-08-12 22:31:07 +08:00
        1
    wuwukai007   102 天前
    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)
        2
    wuwukai007   102 天前
    使用这种曲线那 fun 的方式,还是不行
        3
    myyou   102 天前
    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
        4
    wuwukai007   102 天前
    @myyou 我试一下,主要是用类装饰器后,函数中如果用 super 方法,拿到的是类装饰器中的 super
        5
    wuwukai007   102 天前
    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
        6
    myyou   102 天前
    你是不是把 def __call__(self, func):这里的 self 传给了 func 函数,导致了 func 的 self 函数被替换?
        7
    wuwukai007   102 天前
    @myyou 在__call__中使用闭包,可以用 functools 装饰,但是还是拿不到本身的类
        8
    myyou   102 天前
    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() 加括号试试
        9
    wuwukai007   102 天前
    @myyou 加了,里面随便放了参数,self 关键字我也改了,不行爱
        10
    wuwukai007   102 天前
    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
        11
    wuwukai007   102 天前
    现在是可以拿到了本身的函数,但是本身函数继承的类中的方法拿不到,报没有方法等
        12
    myyou   102 天前
    resp = super(generics.ListCreateAPIView,self).list(request,*args,**kwargs)
    改称 super().list(request,*args,**kwargs)
        13
    myyou   102 天前
    super()方法会使用类的 mro 表第二个类的实例,所以用 super 的时候要注意一点
        14
    wuwukai007   102 天前
    @myyou 我傻 b 了,我的 hander 里面用 self 关键字,调用装饰器中继承的方法,func 中用 selff,使用本身的实例就好了 多谢!
    http://www.chaoyue.red/static/media/1565602027(1).jpg
    留言被限制半小时…
        15
    vkhsyj   102 天前
    update_wrapper,进源码看一下 wraps 怎么实现的就知道怎么做了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   899 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 24ms · UTC 22:28 · PVG 06:28 · LAX 14:28 · JFK 17:28
    ♥ Do have faith in what you're doing.