本文介绍:高阶函数,嵌套函数,以及由前面两个组成的装饰器
一、高阶函数:以下两种情况都是高阶函数
1、将函数名当成参数传递给另外一个函数(作用:不修改被传递函数源代码就可以添加新功能):
import time
def a():
time.sleep(1)
print("This is A funciton...")
# b函数相当于给a函数附加了一个计算时间的功能,但未修改a的源代码
def b(func):
print(func) # 打印func的内存地址
start_time = time.time()
func() # 调用a()
end_time = time.time()
print("a函数运行时间为:%s秒" % (end_time - start_time))
b(a) # 将a函数当成一个变量传递给b
2、将函数名当成返回值返回给另外一个函数(作用:不修改被传递函数调用方式就可以添加新功能):
import time
def a1():
time.sleep(1)
print("This is A1 funciton...")
# b1函数相当于给a1函数附加了一个计算时间的功能,但未修改a的源代码,也未修改a1的调用方式
def b1(func):
start_time = time.time()
func() # 调用a()
end_time = time.time()
print("a函数运行时间为:%s秒" % (end_time - start_time))
return func
a1 = b1(a1) # 将a1函数当成一个变量传递给b1
a1() # 调用未改变a1的调用方式,依然是a1()调用,只不过此时的a1已经通过b1装饰过了。
二、嵌套函数:在函数内部定义一个新的函数,注意:函数内部根据就近原则一层层往外寻找变量
x = 0
def grandpa():
x = 1
def dad():
x = 2
def son():
x = 3
print(x)
son()
dad()
grandpa()
三、装饰器:
1、定义:在不修改函数代码和调用方式的前提下对该函数实现新功能的编程范式,形式上是利用高阶和嵌套函数的特性,高阶函数 + 嵌套函数 = 装饰器,
所以装饰器本质上是一个未其他函数添加新功能的函数,而且不破坏原有代码。
2、原则:
a、不能修改被装饰函数的代码,此项可以防止修改以后对原来的程序逻辑造成影响
b、不能修改被修饰函数的调用方式,比如原来是test()这样调用的,不能改成test(参数1)或者改名成test2()调用,这也是为了让原来的旧代码逻辑不会出现问题导致程序运行失败。
c、综上所述,也就是说被装饰的函数感觉不到装饰器的存在,装饰器是透明的。
3、如何实现装饰器?
a、函数也是一个变量,函数名是变量名,函数执行体就是具体的函数值,所以将函数名赋值给别的函数,在别的函数内部就可以直接使用该函数。
b、单层装饰器:将函数名当成变量传递给另外一个函数,以达到装饰添加新功能的目的。
def timer(func):
def deco(*args,**kwargs): #这是一个嵌套函数,将*args和**kwargs可以允许外界传入任意个数的位置和关键词参数进来
start_time = time.time()
func(*args,**kwargs)
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
return deco
@timer #@timer标签就相当于这句话 test1 = time(test1) 将test1函数变量名传给装饰器
def test1():
time.sleep(1)
print("This is test1")
@timer # test2 = time(test2)
def test2(name,age):
time.sleep(2)
print("This is %s age:%d"%(name,age))
test1()
test2("test2",23)
c、通过嵌套函数两层装饰器,可以让装饰器传递参数
def outside(arg_type):
def inside(func):
def deco(*args, **kwargs):
return_value = ""
if arg_type == "1":
print("加载功能1")
return_value = func(*args, **kwargs)
print("加载功能2")
elif arg_type == "2":
print("加载功能3")
return_value = func(*args, **kwargs)
print("加载功能4")
else:
return_value = func(*args, **kwargs)
print("加载功能5")
return return_value # 这个返回值可以让被装饰的func函数的返回值传到外面
return deco
return inside
@outside(arg_type="1") # 在打标签装饰的同时,还可以传递参数给外层outside
def test1():
print("This is test1")
return "test1"
@outside(arg_type="2")
def test2():
print("This is test2")
return "test2"
@outside(arg_type="3")
def test3(1,2):
print("This is test3")
return "test3"
# test1,test2和test3的的调用方式和其内部代码都未改变,但是通过装饰器却添加了新功能
print(test1())
print(test2())
print(test3())