闭包(closure)是函数式编程的重要的语法结构。
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
def outer(): x = 1 def inner(): print(x) return inner f = outer() f()
inner就是内部函数,inner里引用了外部作用域的变量x(x在外部作用域outer里面,不是全局作用域),则这个内部函数inner就是一个闭包。
闭包=函数块+定义函数时的环境,inner就是函数块,x就是环境。
装饰器
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
简单的装饰器函数:
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
import time def shoe_time(f): def inner(): start = time.time() f() end = time.time() print(end-start) return inner @shoe_time #foo = shoe_time(foo) def foo(): #start = time.time() print("foo......") time.sleep(2) #end = time.time() #print(end-start) #2.0001144409179688 #foo() @shoe_time #bar = shoe_time(bar) def bar(): # start = time.time() print("bar......") time.sleep(3) #end = time.time() #print(end-start) #3.001171588897705 #bar() #shoe_time(foo) #2.0001142024993896 #shoe_time(bar) #3.001171588897705 foo() #foo...... # 2.0001144409179688 bar() # bar...... # 3.00017142295837
带参数的被装饰函数
#功能函数加参数 import time def shoe_time(f): def inner(x,y): start = time.time() f(x,y) end = time.time() print(end-start) return inner @shoe_time def add(a,b): print(a+b) time.sleep(3) #@shoe_time # def foo(): # print("foo......") # time.sleep(2) # @shoe_time # def bar(): # print("bar......") # time.sleep(3) # add(1,3) #4 #3.000171661376953 #不定长参数 import time def shoe_time(f): def inner(*x,**y): start = time.time() f(*x,**y) end = time.time() print(end-start) return inner @shoe_time def add(*a,**b): sum = 0 for i in a: sum += i print(sum) time.sleep(3) #@shoe_time # def foo(): # print("foo......") # time.sleep(2) # @shoe_time # def bar(): # print("bar......") # time.sleep(3) # add(1,3,4,6,78) #92 #3.000171661376953
带参数的装饰器
装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如@shoe_time,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。
#带参数的装饰器 import time def logger(flag=""): def shoe_time(f): def inner(*x,**y): start = time.time() f(*x,**y) end = time.time() print(end-start) if flag == "true": with open("日志记录", "a",encoding="utf8") as g: g.write("值为: %s 时间为: %s "%(f(*x),(end-start))) return inner return shoe_time @logger("true") #@show_time def add(*a,**b): Sum = 0 for i in a: Sum += i print(Sum) time.sleep(3) return Sum @logger("abc") def foo(): print("foo......") time.sleep(2) # @shoe_time # def bar(): # print("bar......") # time.sleep(3) add(1,3,4,6,78) #92 #3.000171661376953 foo()
@logger("true") 做了两件事:
(1)@ogger("true"):得到闭包函数show_time,里面保存环境变量flag
(2)@time :add=show_time(add)
上面的logger是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器(一个含有参数的闭包函数)。当我 们使用@logger("true")调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。