一、闭包
如果在一个函数的内部定义了另外一个函数,外部的函数就叫它外函数,内部的函数就叫他内函数
闭包的条件
- 在一个外函数中定义了一个内函数
- 内函数里运行了外函数的临时变量
- 并且外函数的返回值是内函数的引用
例子:
def outer(a)
b = 10
def inner():
print(a+b)
return inner
if __name__ == 'main':
demo = outer(5)
demo() ## 15
一个函数结束的时候会把自己内部的临时变量都释放了。但是闭包中,外函数发现,自己的临时变量会在将来的内部函数中被使用,所以在自己结束之后,返回内函数的同时,会把外函数的临时变量和内函数给绑定起来。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量。
补充:闭包中想要修改外函数中的变量,需要使用nonlocal 来修饰该变量然后才能对该变量进行改变
二、装饰器
先来个栗子:
import time
def showtime(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print('Running :%d s' % (end_time - start_time))
return wrapper
@showtime
def foo1():
print('foo1')
time.sleep(1)
if __name__ == '__main__':
foo1()
## 输出
foo1
Running :1 s
从上面的结果可以很清楚的了解到装饰器的原理
实际上,上面装饰器的原型为:
def showtime(func):
def wrapper():
print('Time start')
start_time = time.time()
func()
end_time = time.time()
print('Running %d s' % (end_time-start_time))
print('Time end')
return wrapper
def foo():
print('foo..')
time.sleep(1)
foo = showtime(foo)
foo()
带有参数的装饰器
import time
def func_argc(pre='Test'):
def showtime(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print('Running :%d s' % (end_time - start_time))
print('pre=%s' % pre)
return wrapper
return showtime
@func_argc(pre='LALA')
def foo1():
print('foo1')
time.sleep(1)
if __name__ == '__main__':
foo1()
# 输出
foo1
Running :1 s
pre=LALA
三、wraps
再举个栗子
def wrapper(f):
def wrapper_function(*args, **kwargs):
"""这个是修饰函数"""
return f(*args, **kwargs)
return wrapper_function
@wrapper
def wrapped():
"""这个是被修饰的函数"""
print('wrapped')
print(wrapped.__doc__) # 输出`这个是修饰函数`
print(wrapped.__name__) # 输出`wrapper_function`
我们发现,返回函数变成了wrapper_function。原因是给wrapped函数添加上了wrapper装饰器相当于wrapped = wrapper(wapped),而wrapper返回的函数类型为wrapper_function。
那么如果我们希望返回为当前函数自己呢?这时候就需要使用上wraps
from functools import wraps
def wrapper(f):
@wraps(f) # 添加上这一句话即可
def wrapper_function(*args, **kwargs):
"""这个是修饰函数"""
return f(*args, **kwargs)
return wrapper_function
@wrapper
def wrapped():
"""这个是被修饰的函数"""
print('wrapped')
print(wrapped.__doc__) # 输出`这个是被修饰的函数`
print(wrapped.__name__) # 输出`wrapped`
参考文献: