Python基础知识——装饰器
装饰器
闭包:
>>> def outer():
x = 6 #外部环境的变量
def inner(): #内部函数
print(x)
return inner #inner即为闭包
>>> f = outer()
>>> f()
6
>>> def outer(a): #外部环境的变量
def inner(): #内部函数
print(a)
return inner #闭包inner
>>> f = outer(6)
>>> f()
6
定义:如果在一个内部函数里,在对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
闭包 = 函数块 + 定义函数时的环境
如上所示,inner()作为返回值,在外部作用域进行调用,而可以访问inner作用域之外的作用域(outer作用域)中的变量,这种现象就叫做闭包
实例:
import time def func1(): time.sleep(1) print('I\'m the first') def func2(): time.sleep(2) print('I\'m no the last') def func3(): time.sleep(1.5) print('Maybe I\'m the last') def func4(): time.sleep(3) print('I\'m the last') func1() func2() func3() func4()
如代码所示,有四个函数分别实现不同的功能
现如今有一个需求,要求每个函数都能把该函数的运行时间输出,该如何修改代码?
方法一:
import time def func1(): start = time.time() time.sleep(1) print('I\'m the first') end = time.time() print(end - start) def func2(): start = time.time() time.sleep(2) print('I\'m no the last') end = time.time() print(end - start) def func3(): start = time.time() time.sleep(1.5) print('Maybe I\'m the last') end = time.time() print(end - start) def func4(): start = time.time() time.sleep(3) print('I\'m the last') end = time.time() print(end - start) func1() func2() func3() func4()
如代码所示,直接把每个函数中的代码修改了,这样就可以实现所需的功能
对于实际的开发环境中,函数应满足封闭性和可扩展性,封闭性就是指函数一旦设计完成,无论是如何实现的,都不应对其内部的实现进行修改,可扩展性是指,函数应支持扩展,及支持增加功能。
方法一显然不符实际,直接对函数内部实现进行修改是不被允许的,而且如果函数量非常大的情况下,这种方式也不切实际。
方法二:
import time def show_time(f): start = time.time() f() end = time.time() print(end - start) def func1(): time.sleep(1) print('I\'m the first') def func2(): time.sleep(2) print('I\'m no the last') def func3(): time.sleep(1.5) print('Maybe I\'m the last') def func4(): time.sleep(3) print('I\'m the last') show_time(func1) show_time(func2) show_time(func3) show_time(func4)
根据方法一的经验,不对函数进行修改,另外由于方法一中实现时,
每个函数中的都是重复代码,所以可以用函数去改进,所以采用高阶函数对代码进行修改
方法二相对于方法一显然有了很大改进,而且通过函数很好的实现了功能
但是,美中不足的是,该方法对于函数的调用方式进行了修改,原本funct1()就可以直接调用该函数,而却需要全部改成show_time()才能调用,不利于其他开发人员进行该函数的调用
而且每次进行功能拓展时,如果都需要修改调用方式,显然不现实
方法三:
import time def show_time(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner def func1(): time.sleep(1) print('I\'m the first') func1 = show_time(func1) def func2(): time.sleep(2) print('I\'m no the last') func2 = show_time(func2) def func3(): time.sleep(1.5) print('Maybe I\'m the last') func3 = show_time(func3) def func4(): time.sleep(3) print('I\'m the last') func4 = show_time(func4) func1() func2() func3() func4()
经过方法一和方法二的总结,方法三通过装饰器很好的实现了函数功能的拓展
装饰器的概念:
- 如上例方法三所示的show_time函数就叫做装饰器函数
- 装饰器本质就是一个函数,用于在不改变函数内部实现的情况下,为函数增加和拓展新的功能
- 装饰器即通过内部实现闭包,而在外部调用内部函数实现已封装函数功能的拓展,这样的函数叫做装饰器
装饰器的另一种使用方法:
import time def show_time(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner @show_time def func1(): time.sleep(1) print('I\'m the first') #func1 = show_time(func1) @show_time def func2(): time.sleep(2) print('I\'m no the last') #func2 = show_time(func2) @show_time def func3(): time.sleep(1.5) print('Maybe I\'m the last') #func3 = show_time(func3) @show_time def func4(): time.sleep(3) print('I\'m the last') #func4 = show_time(func4) func1() func2() func3() func4()
通过在未修改的函数前添加@+装饰器函数,可以替换在该函数之后的赋值语句
更加简单、方便, 而且逼格高
带参数的功能函数:
import time #必须参数 def show_time(f): def inner(x, y): start = time.time() f(x, y) end = time.time() print(end - start) return inner @show_time def add(x, y): print(x+y) time.sleep(1) add(1,2) import time #不定长参数 def show_time(f): def inner(*args): start = time.time() f(*args) end = time.time() print(end - start) return inner @show_time def add(*args): sum = 0 for i in args: sum+=i print(sum) time.sleep(1) add(1, 2, 3, 4, 5)
如果功能函数带参数时,只需直接修改装饰器里调用参数的对应位置即可
另外,对于用装饰器装饰不同参数类型的功能函数时,只需重新写一个参数不同的装饰器即可
带参数的装饰器:
假如同样对于之前的实例,需要再加上一个功能:
对于func1和func3实现输出日志的功能,而对于func2和func4不实现该功能
此时该如何去完成
import time def outer(flag = 'False'): def show_time(f): def inner(): start = time.time() f() end = time.time() print(end - start) if flag == 'True': print('log ... ...') return inner return show_time @outer('True') def func1(): time.sleep(1) print('I\'m the first') @outer() def func2(): time.sleep(2) print('I\'m no the last') @outer('True') def func3(): time.sleep(1.5) print('Maybe I\'m the last') @outer() def func4(): time.sleep(3) print('I\'m the last') func1() func2() func3() func4()
如代码所示,在原本的装饰器外又嵌套了一层函数,又实现了一层闭包
外层函数的主要作用就是为装饰器引入了一个参数,使得装饰器可以进行有选择的判断

浙公网安备 33010602011771号