首页 > 代码库 > python装饰器
python装饰器
网上面有很多优秀的文章写得很好,但是每个人的思路和接受的方式都不一样,我选用了自己能看得懂再加上自己的理解写了这篇博客,将分为多步实现对装饰器的理解,作为新手入门级别,另外会在结束后,给上我认为优秀文章的链接。。。。帮助有缘人彻底起飞
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
原则:1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方法
废话不多说,开整吧!
第一步:准备给一个函数添加一个新的功能
def foo(): time.sleep(3) print(‘in the foo‘) foo()
我首先想到会这样做
def foo(): start_time = time.time() time.sleep(3) print(‘in the foo‘) end_time = time.time() print(‘code run time is %s‘%(end_time-start_time)) foo()
直接修改源码,违背原则1,显然任务量很大,而且很low
于是乎,我想到了似low非low
def timer(): start_time = time.time() foo() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) timer()
或者
def timer(func): start_time = time.time() func() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) timer(foo) 直接写一个计算运行时间的函数,把需要添加功能的函数放进来,这样就可以不改变源码了,但是调用方法却从foo()---->timer()和timer(foo),违背原则2,假设foo()在多处被修改,
那么我们是不是也要去把所有的foo()换成timer(foo)呢?
但是不要着急,因为我们已经实现了不改变源码那一步,现在只需要将调用方法timer(foo)变成-----》foo()即可,我们何不把timer赋值给foo,等等,timer似乎带有一个参数.......
显然你不可能把timer(foo)赋值给foo,然后再调用foo(),这个为什么不能的原因如果不知道就扇自己一个大嘴巴子吧........什么?扇完还不知道!timer(foo)是函数调用的结果,结果
能当函数调用吗.....我们要想timer(foo)不是直接产生调用结果,那就必须让他返回一个与foo参数一致的函数,然后就可以把timer(foo)赋值给foo,再调用foo()
怎么才能做到这一点呢?必须要用到嵌套函数,在timer函数体里再def定义一个函数,然后返回这个函数
def timer(func): def deco(): start_time = time.time() func() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return deco foo=timer(foo) foo()
可以说,基本上已经完成了一个装饰器,粘贴一段话以示尊敬
在这个例子中,函数进入和退出时需要计时,这被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。面向切面编程还有相当多的术语,这里就不多做介绍,感兴趣的话可以去找找相关的资料。
你以为就这样结束了???so young
现在foo()里有参数了
def timer(func): def deco(a,b): start_time = time.time() ret = func(a,b) end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return ret return deco @timer def foo(a,b): time.sleep(3) print(‘in the foo‘) return a+b foo(1,2)
或许大家注意到了@timer,这个叫做语法糖,有了这个就可以省去foo= timer(func)
现在不确定往foo()传什么参数,还好python里面有*args和**kwargs,可变参数
def timer(func): def deco(*args,**kwargs): start_time = time.time() ret = func(*args,**kwargs) end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return ret return deco @timer def foo(a,b): time.sleep(3) print(‘in the foo‘) return a + b @timer def foo2(a,b,c): time.sleep(3) print(‘in the foo‘) return a + b +c foo(1,2) foo2(1,2,3)
还可以让装饰器带参数,今晚就先到这里了,明天还要上班,待更新
python装饰器