装饰器: 本质就是函数,为其他函数添加附加功能
装饰器原则:
不修改被装饰函数的源代码
不修改被装饰函数的调用方式
装饰器=高阶函数 + 函数嵌套 +闭包
定义:
函数接收的参数是一个函数名
函数的返回值是一个函数名
满足上述任意一个条件的函数即为高阶函数
高阶函数示例
def foo(): print("hello") # 函数名作为参数 def func_1(func): print("heiheihei") func() print("world") # 函数名作为返回值 def func_2(func): print("return value: %s" % func) return func # 函数名作为参数和返回值 def func_3(func): print("from func_3") return func func_1(foo) print('----------------') func_2(foo) print('----------------') f = func_3(foo) f() # f是func_3的返回值,即为函数foo的函数地址,f()执行函数foo输出“hello” >>heiheihei hello world ---------------- return value: <function foo at 0x00000276CAAA3E18> ---------------- from func_3 hello使用高阶函数实现在不改变函数调用方式的前提下,增加函数的功能
import time # 为foo函数增加函数运行时间计时功能 def foo(): time.sleep(2) print("function foo running") def timer(func): start_time = time.time() func() stop_time = time.time() print("running time %s" % (start_time - stop_time)) return func foo = timer(foo) foo() >>function foo running running time -2.0002999305725098 function foo running # 以foo()的形式运行函数foo,实现了不改变函数调用方式运行函数 # 但运行过程中多执行了一次foo, # 第一次执行是timer函数中的func() # 第二次执行是timer函数返回了foo函数名,最后运行foo()再次运行了foo原函数根据以上示例可以得出单纯使用高阶函数无法完全实现在不改变函数调用方式的基础下增加函数的功能
定义:在函数里面嵌套定义函数
def country(name): print('country is %s' %name) def province(): print('guangdong') def city(): print('shenzhen') city() province() country('china') >>country is china guangdong shenzhen定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
def country(name): print('country is %s' %name) def province(): print('province is %s' % name) def city(): print('city is %s' % name) city() province() country('china')province()函数就是一个闭包
上述示例实现了为foo函数增加函数运行时间计时的功能,如果将f改为foo,则实现了不改变函数的调用方式同时增加了函数的功能,如下所示
import time def timer(func): def inner(): start_time = time.time() func() stop_time = time.time() print("running time is %s" % (stop_time- start_time)) return inner def foo(): print("foo function") time.sleep(2) foo = timer(foo) foo() >> foo function running time is 2.000906229019165 # 最后执行的foo函数相比于最初定义的foo函数,实现了增加函数运行时间计时的功能到此基本实现了在不改变函数的调用方式以及函数源码的前提下,实现了增加函数功能,但还需要做一步函数赋值的操作,如果其他函数需要怎加同样的功能,还要对其他函数做赋值操作,这是很麻烦的。
使用装饰器可以避免这样的麻烦,只要在添加功能的目标函数前添加一行代码:@功能函数。实现方法如下所示
import time def timer(func): def inner(): start_time = time.time() func() stop_time = time.time() print("running time is %s" % (stop_time- start_time)) return inner @timer def foo(): print("foo function") time.sleep(2) foo() >>foo function running time is 2.000242233276367