为了账号安全,请及时绑定邮箱和手机立即绑定

如何用装饰器类装饰实例方法?

如何用装饰器类装饰实例方法?

白板的微信 2019-11-02 09:52:22
考虑这个小例子:import datetime as dtclass Timed(object):    def __init__(self, f):        self.func = f    def __call__(self, *args, **kwargs):        start = dt.datetime.now()        ret = self.func(*args, **kwargs)        time = dt.datetime.now() - start        ret["time"] = time        return retclass Test(object):    def __init__(self):        super(Test, self).__init__()    @Timed    def decorated(self, *args, **kwargs):        print(self)        print(args)        print(kwargs)        return dict()    def call_deco(self):        self.decorated("Hello", world="World")if __name__ == "__main__":    t = Test()    ret = t.call_deco()哪个打印Hello(){'world': 'World'}为什么self参数(应该是Test obj实例)没有作为第一个参数传递给装饰函数decorated?如果我手动进行操作,例如:def call_deco(self):    self.decorated(self, "Hello", world="World")它按预期工作。但是,如果我必须事先知道某个函数是否装饰,它就破坏了装饰器的全部目的。这里的模式是什么,还是我误会了什么?
查看完整描述

3 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

您首先必须了解函数如何成为方法以及如何self“自动”注入。


一旦知道这一点,“问题” 就很明显了:您正在decorated用Timed实例装饰函数-IOW Test.decorated是Timed实例,而不是function实例-并且您的Timed类不会模仿协议的function类型实现descriptor。您想要的内容如下所示:


import types


class Timed(object):

    def __init__(self, f):

        self.func = f


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

        start = dt.datetime.now()

        ret = self.func(*args, **kwargs)

        time = dt.datetime.now() - start

        ret["time"] = time

        return ret


   def __get__(self, instance, cls):           

       return types.MethodType(self, instance, cls)


查看完整回答
反对 回复 2019-11-02
  • 3 回答
  • 1 关注
  • 873 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信