当前位置: 首页 > 科技观察

为什么不使用这样的装饰器呢?

时间:2023-03-12 09:41:17 科技观察

最近几周收到了几个读者关于装饰器使用的问题,今天一并回复。1.问题大概是下面的。我想定制一个Python装饰器。我可以写这样的装饰器吗?如果不是,为什么?importdatetimeimporttimedefprint_time(g):deff():print('开始执行时间')print(datetime.datetime.today())g()print('结束时间')print(datetime.datetime.today())f()下面使用print_time修饰foo函数:@print_timedeffoo():time.sleep(2)当print('helloworld')调用foo函数时,抛出如下异常:foo()----------------------------------------------------------------------TypeErrorTraceback(mostrecentcalllast)in---->1foo()TypeError:'NoneType'objectisnotcallable所以,根据上面的print_time装饰器的定义,它肯定是行不通的。2.为什么不行要理解为什么不行,首先要知道装饰器的语法本质。其实很简单,@print_time修饰foo函数就等于:foo=print_time(foo)就是这行代码,没有别的。因为上面的print_time没有返回值,赋值给foo函数后,foo函数就变成了None,所以调用foo()时抛出'NoneType'objectisnotcallable也就不足为奇了。3、print_time怎么写一个函数需要返回,所以赋值给foo函数后,正确的写法如下:importdatetimeimporttimedefprint_time(g):deff():print('开始执行时间')print(datetime.datetime.today())g()print('结束时间')print(datetime.datetime.today())returnf装饰foo:@print_timedeffoo():time.sleep(2)print('helloworld')调用foo,运行结果如下:foo()开始执行时间2021-04-0222:32:49.114124helloworld结束时间2021-04-0222:32:51.119506一切正常类内其他任何函数和方法。修饰任意函数foo2:@print_timedeffoo2():print('thisisfoo2')修饰类中的方法foo3,需要对原来的print_time稍作修改:defprint_time(g):deff(*args,**kargs):print('开始执行时间')print(datetime.datetime.today())g(*args,**kargs)print('结束时间')print(datetime.datetime.today())returnf为foo3添加print_time装饰MyClass类中的方法:classMyClass(object):@print_timedeffoo3(self):print('thisisamethodofclass')执行结果如下:MyClass().foo3()开始执行时间2021-04-0223:16:32.094025thisisamethodofclass结束时间2021-04-0223:16:32.094078以上是对装饰器的通俗解释,平时可以通过多种方式使用,让我们的代码更加精炼和可读。