闭包
如果一个函数用到了它作用域外面的变量 那么这个变量和这个函数之间的环境就叫闭包
如果需要在闭包内修改外部函数的变量需要nonlocal声明
在使用闭包时 外部函数的返回值一定是内部函数的引用
def foo(n):
def call(i):
nonlocal n # 输入 nonlocal 是修改外部变量 不写 nonlocal 是定义局部变量
n = 100
return n + i
return call
num = foo(10)
sum = num(1)
sum == 101
在函数 plus没有n的值时会通过向上查找机制寻找外部函数作用域下的变量 得到在Foo中n的值
装饰器
装饰器又叫做语法糖
装饰器的作用就是在不改变原函数的基础上增加功能
装饰器的下方如果不是函数程序会继续向下运行当遇到函数时再回头进行装饰
多个装饰器同时装饰一个函数时运行到@时先运行最下面的@当下面的@装饰函数后变为一个函数 再运行上面的@对函数进行装饰
装饰器(decorator)功能
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
无参数装饰器
def set_func(func):
def call_func():
print("-----1-----")
func()
print("-----2-----")
return call_func
@ set_func # 等价于 test = set_func(test)
def test():
print("-----test-----")
# test = set_func(test)
# test()
test() # 使用装饰器后此时 test() 等价于上面注释的功能
添加的功能要么在原函数之前执行要么在原函数之后执行 并不能在原函数执行中添加新加的代码
有参数装饰器
def set_func(func):
print("程序执行到@时会调用闭包外的函数")
def call_func(n):
func(n)
return call_func
@ set_func
def test(num):
print("-----test-----")
test(100)
装饰器在程序执行到@符号时就被执行 所以@set_func 等同于执行了 test = set_func(test)
不定长参数装饰器
def set_func(func):
def call_func(*args, **kwargs):
func(*args, **kwargs)
return call_func
@set_func
def test(num, *args, **kwargs):
print("---------%d" % num, args, kwargs)
test(10)
test(10, 20)
test(10, 20, n=30)
需要传递不定长参数 或者不传递参数都可以使用*args,**kwargs的方式接收参数
有返回值的函数装饰器
def set_func(func):
def call_func(*args, **kwargs):
return func(*args, **kwargs) # return 再次返回给test()
return call_func
@set_func
def test(num, *args, **kwargs):
print("---------%d" % num, args, kwargs)
return "done" # return 返回给调用方func()
ret = test(10)
print(ret) # 如果闭包内不返回将打印None
对带有返回值的函数进行装饰时 需要在闭包内返回传递的值
通用装饰器
def set_func(func):
def call_func(*args, **kwargs):
return func(*args, **kwargs)
return call_func
@set_func
def test(num, *args, **kwargs):
print(num, args, kwargs)
return "ok"
test(10, 20, n=30)
如果没有参数的函数进行装饰*args也代表空的元组
如果对没有返回值的函数进行装饰时也在闭包内返回 其实传递的是None
以上都不影响程序
带参数的装饰器
带参数的装饰器执行过程和普通装饰器不一样
@set_outer(num)表示:
- 执行
set_outer(num)函数 - 用返回的函数
set_func(func)对下面的函数进行装饰
def set_outer(level):
def set_func(func):
def call_func(*args, **kwargs):
if level == 1:
print("------%d------" % level)
elif level == 2:
print("------%d------" % level)
return func(*args, **kwargs)
return call_func
return set_func
@set_outer(1)
def test1(num, *args, **kwargs):
print(num, args, kwargs)
return "ok"
@set_outer(2)
def test2(num, *args, **kwargs):
print(num, args, kwargs)
return "ok"
test1(10)
test2(10, 20, n=30)