对于一般的函数我们无法通过直接引用来对嵌套函数中的内层函数进行操作,而闭包很好地解决了这一问题,示例如下:
def power(exp):
def exp_of(base):
return base ** exp
return exp_of
square = power(2)
cube = power(3)
print(square(2), square(3))
print(cube(2), cube(3))
## 4 9
## 8 27
同时使用闭包和nonlocal时可以使得函数内部参数不被初始化。
def outer():
x=0
y=0
def inner(x1, y1):
nonlocal x, y
x+=x1
y+=y1
print(f"Now,x={x},y={y}")
return inner
move = outer()
move(1, 2)
move(-2, -3)
## Now,x=1,y=2
## Now,x=-1,y=-1
# 可以看见每次调用时,函数内部的x和y并没有被初始化。
与闭包相反,我们可以通过将函数作为函数的参数:
def myfun():
print("正在调用myfun...")
def report(func):
print("开始调用函数")
func()
print("函数调用完毕")
report(myfun)
## 开始调用函数
## 正在调用myfun...
## 函数调用完毕
通过使用装饰器,我们可以避免再去函数中直接调用函数。
import time
def times(func):
def call_func():
print("开始运行该程序...")
start = time.time()
func()
stop = time.time()
print(f"一共耗费了{(stop-start)*1000:.2f}ms")
return call_func
@times
def myfun():
time.sleep(2)
print("I Love Cloud")
myfun()
## 开始运行该程序...
## I Love Cloud
## 一共耗费了2001.42ms
装饰器的实现使用到了闭包的方法,其中的@times便是相当于 myfun = times(myfun)。
对于多个修饰器同时使用在同一个函数上也是可行的。
def add(func):
def inner():
x=func()
return x+1
return inner
def square(func):
def inner():
x=func()
return x*x
return inner
def cube(func):
def inner():
x=func()
return x*x*x
return inner
@square
@add
@cube
def myfun():
return 2
print(myfun())
## 81
#可以看出,函数先调用cube,再调用add,最后调用square
给装饰器传递参数:
import time
def logger(msg):
def times(func):
def call_func():
start = time.time()
func()
stop = time.time()
print(f"[{msg}]一共耗费了{stop-start:.2f}s")
return call_func
return times
@logger(msg="A")
def funa():
time.sleep(1)
print("正在调用funa...")
@logger(msg="B")
def funb():
time.sleep(1)
print("正在调用funb...")
funa()
funb()
## 正在调用funa...
## [A]一共耗费了1.00s
## 正在调用funb...
## [B]一共耗费了1.00s
对于给修饰器传递参数,无非是多了一层函数的嵌套。其等价于
import time
def logger(msg):
def times(func):
def call_func():
start = time.time()
func()
stop = time.time()
print(f"[{msg}]一共耗费了{stop-start:.2f}s")
return call_func
return times
def funa():
time.sleep(1)
print("正在调用funa...")
def funb():
time.sleep(1)
print("正在调用funb...")
funa = logger(msg="A")(funa)
funb = logger(msg="A")(funb)
funa()
funb()