闭包
1.作用域L_E_G_B(局部、内嵌、全局...):
1 x=10#全局 2 3 def f(): 4 a=5 #嵌套作用域 5 def inner(): 6 count = 7 #局部变量 7 print a 8 return 1
从内往外寻找 a 。
2.高阶函数
a.函数名可以作为参数输入
b.函数名可以作为返回值
3.闭包
1 def outer(): 2 x=10 3 def inner(): #条件1 inner是内部函数 4 print(x) #条件2 外部环境的一个变量 5 6 return inner #结论: 内部函数inner就是一个闭包 7 8 outer()()#调用inner 9 #同上 10 f = outer()#获得inner 11 f()#调用执行inner 12 13 #不能直接调用inner,因为inner为局部变量,全局无法调用
执行结果
10
10
Process finished with exit code 0
第10行,获得inner变量,第11行执行inner函数,而执行inner函数时(在外部执行),其中x变量既不属于inner函数内部变量,也不属于全局变量,按理应该报错却没报错,这种现象称为闭包。
定义:如果在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
在内部函数里(inner函数中),对在外部作用域的变量(x)进行引用(print),那么内部函数(inner)就被认为是闭包。
装饰器
1 import time 2 3 def foo(): 4 print("foo.....") 5 time.sleep(2) 6 7 def bar(): 8 print("bar.....") 9 time.sleep(3) 10 11 def show_time(f): #函数名作参数 12 start = time.time() 13 f() 14 end = time.time() 15 print("spend %s" % (end - start)) 16 17 18 show_time(bar)
函数名作参数,减少重复代码。
执行结果:
bar..... spend 3.0022976398468018 Process finished with exit code 0
但是以上方法改变了调用方式,加上所需时间功能后,不是直接用foo,而是用show_time,这样对所有使用foo函数的代码都需修改,违背了封闭开放原则。
1 import time 2 3 def foo(): 4 print("foo.....") 5 time.sleep(2) 6 7 def bar(): 8 print("bar.....") 9 time.sleep(3) 10 11 def show_time(f): #函数名作参数 ,装饰器 12 def inner(): 13 start = time.time() 14 f() 15 end = time.time() 16 print("spend %s" % (end - start)) 17 return inner 18 19 foo = show_time(foo) 20 foo()
show_time即为装饰器,inner函数为闭包,f函数名变量即为外部作用域变量。
执行结果:
foo..... spend 2.00213360786438 Process finished with exit code 0
但是以上方法还需要自己赋值,不够简便、优雅。
优雅的写法:
1 import time 2 3 def show_time(f): #函数名作参数 ,装饰器 4 def inner(): 5 start = time.time() 6 f() 7 end = time.time() 8 print("spend %s" % (end - start)) 9 return inner 10 11 @show_time # foo = show_time(foo), 给foo函数添加一个计算所需时间的功能 12 def foo(): 13 print("foo.....") 14 time.sleep(2) 15 16 #foo = show_time(foo) 17 foo()
11行,给foo函数添加一个计算所需时间的功能,@show_time,可理解为foo = show_time(foo)。
执行结果:
foo..... spend 2.002133369445801 Process finished with exit code 0
被装饰函数参数(功能函数加参数):
1 import time 2 3 def show_time(f): #函数名作参数 ,装饰器 4 def inner(x, y): 5 start = time.time() 6 f(x, y) 7 end = time.time() 8 print("spend %s" % (end - start)) 9 return inner 10 11 @show_time # add = show_time(add), 给add函数添加一个计算所需时间的功能 12 def add(a, b): 13 print(a + b) 14 time.sleep(1) 15 16 #foo = show_time(foo) 17 add(1, 2)
执行结果:
3 spend 1.0010321140289307 Process finished with exit code 0
不定长参数:
1 import time 2 3 def show_time(f): #函数名作参数 ,装饰器 4 def inner(*x, **y): 5 start = time.time() 6 f(*x, **y) 7 end = time.time() 8 print("spend %s" % (end - start)) 9 return inner 10 11 @show_time 12 def add(*a, **b): # a为元组 13 sums = 0 14 for i in a: 15 sums += i 16 print(sums) 17 time.sleep(1) 18 19 20 add(1, 2, 5, 7, 9)#不定长参数
其中a为元组。
执行结果:
24 spend 1.0011086463928223 Process finished with exit code 0
装饰器参数:
1 import time 2 3 def logger(flag=''):#默认空 4 5 def show_time(f): # 函数名作参数 ,装饰器 6 def inner(*x, **y): 7 start = time.time() 8 f(*x, **y) 9 end = time.time() 10 print("spend %s" % (end - start)) 11 if flag == 'true': 12 print('日志记录') 13 return inner 14 return show_time 15 16 def show_time(f): #函数名作参数 ,装饰器 17 def inner(*x, **y): 18 start = time.time() 19 f(*x, **y) 20 end = time.time() 21 print("spend %s" % (end - start)) 22 return inner 23 24 @logger('true') # 相当于@show_time,不过有了一个flag变量,相当于闭包 25 def add(*a, **b): # a为元组 26 sums = 0 27 for i in a: 28 sums += i 29 print(sums) 30 time.sleep(1) 31 33 add(1, 2, 5, 7, 9)#不定长参数 34 35 @logger() 36 def bar(): 37 print("bar......") 38 time.sleep(3) 39 40 bar()
装饰器加参数flag,决定是否输出日志,此时show_time为闭包。
执行结果:
24 spend 1.001152515411377 日志记录 bar...... spend 3.00311541557312