闭包
如果一个函数
用到了它作用域
外面的变量 那么这个变量
和这个函数
之间的环境就叫闭包
如果需要在闭包
内修改外部函数
的变量需要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)