闭包、装饰器
闭包
-
通俗来讲,闭包就相当于函数的嵌套 ,在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
# ======================程序==================== def test(number): def test_in(number_in): print("in test_in 函数, number_in is %d" % number_in) return number+number_in # 其实这里返回的就是闭包的结果 return test_in # 给test函数赋值,这个20就是给参数number ret = test(20) # 注意这里的100其实给参数number_in print(ret(100)) #注 意这里的200其实给参数number_in print(ret(200)) # ====================运行结果=================== in test_in 函数, number_in is 100 120 in test_in 函数, number_in is 200 220
-
闭包实际例子
# ====================程序=============== def line_conf(a, b): def line(x): return a*x + b return line line1 = line_conf(1, 1) line2 = line_conf(4, 5) print(line1(5)) print(line2(5)) # ====================结果=============== 6 25
这个例子中,函数
line
与变量a,b
构成闭包。在创建闭包的时候,我们通过line_conf
的参数a,b
说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)
。我们只需要变换参数a,b
,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。
-
在闭包内也可以修改外部函数中的变量
# ====================程序=============== def counter(start=0): def incr(): nonlocal start start += 1 return start return incr c1 = counter(5) print(c1()) print(c1()) c2 = counter(50) print(c2()) print(c2()) print(c1()) print(c1()) print(c2()) print(c2()) # ====================结果=============== 6 7 51 52 8 9 53 54
每一次创建闭包实际上是分别分配了一个空间给
c1和c2
,他们相互独立
装饰器
- 装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象
- 装饰器(decorator)功能:
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
-
先看一段代码
def t1(): print('执行前...') print('t1------ 我被执行了。。') print('执行完成') def t2(): print('执行前...') print('t2------ 我被执行了。。') print('执行完成') def t3(): print('执行前...') print('t3------ 我被执行了。。') print('执行完成')
-
在看一段代码
# ===================程序================ def set_func(func): def call_func(): print('执行前...') func() print('执行完成') return call_func @set_func def t1(): print('t1------ 我被执行了。。') @set_func def t2(): print('t2------ 我被执行了。。') @set_func def t3(): print('t3------ 我被执行了。。') t1() # ===================结果================ 执行前... t1------ 我被执行了。。 执行完成
这两段代码的效果都是一样的,而下面的则使用了 装饰器 ,由此可见,使用装饰器可以在不改变原函数的情况下,对原函数的功能进行扩展!
@set_func
等价于t1 = set_func(t1)
执行过程:当执行
@set_func
时,相当于把t1
当作实参传给了set_func()
,这时 形参func
指向了函数t1
,然后到执行return call_func
时,就是返回call_func
这个引用给t1
(因为是t1
调用的set_func
),也就是说这时t1
指向的就是call_func()
函数,然后调用t1()
时,就相当于调用call_func()
,执行到func()
时,因为它指向的是t1
里面的语句,所以执行的是print('t1------ 我被执行了。。')
语句 -
装饰有参数无返回值的函数
# ===================程序================ def set_func(func): def call_func(num): print("11111111111") func(num) return call_func @set_func def test1(num): print("-----test1-----%d" % num) test1(100) # ===================结果================ 11111111111 -----test1-----100
因为函数带有参数,所以指向
test1
的func
在调用时也需带参数传递,故而call_func
也需要有参数传给func
-
装饰不定长参数的函数
# ===================程序================ def set_func(func): def call_func(*args, **kwargs): print("11111111111") func(*args, **kwargs) return call_func @set_func def test1(num, *args, **kwargs): print("-----test1-----%d" % num) print("-----test1-----", args) print("-----test1-----", kwargs) test1(100) test1(100, 200) test1(100, 200, 300, mm=100) # ===================结果================ 11111111111 -----test1-----100 -----test1----- () -----test1----- {} 11111111111 -----test1-----100 -----test1----- (200,) -----test1----- {} 11111111111 -----test1-----100 -----test1----- (200, 300) -----test1----- {'mm': 100}
-
装饰带有返回值的函数
# ===================程序================ def set_func(func): def call_func(*args, **kwargs): print("11111111") return func(*args, **kwargs) # 返回原函数的返回值 return call_func @set_func def test1(num, *args, **kwargs): print("-----test1-----%d" % num) print("-----test1-----", args) print("-----test1-----", kwargs) return "hhhhh" ret = test1(100) print(ret) # ===================结果================ 11111111 -----test1-----100 -----test1----- () -----test1----- {} hhhhh
因为原函数有返回值,所以我们需要在装饰器中接收原函数的返回值并返回
-
同一个装饰器装饰多个函数
# ===================结果================ def set_func(func): def call_func(num): print("11111111111") func(num) return call_func @set_func def test1(num): print("-----test1-----%d" % num) @set_func def test2(num): print("-----test1-----%d" % num) test1(100) test2(200) # ===================结果================ 11111111111 -----test1-----100 11111111111 -----test1-----200
用一个函数装饰器可对多个函数进行装饰,每次装饰时,在没调用函数之前就已经装饰了,每次装饰相当一个闭包
-
多个装饰器装饰一个函数
# ===================结果================ def set_func1(func): print("---开始装饰权限1的功能---") def call_func(*args, **kwargs): print("----这是权限1----") return func(*args, **kwargs) return call_func def set_func2(func): print("----开始装饰权限2的功能----") def call_func(*args, **kwargs): print("----这是权限2-----") return func(*args, **kwargs) return call_func @set_func1 @set_func2 def test1(num, *args, **kwargs): print("-----test1-----%d" % num) print("-----test1-----", args) print("-----test1-----", kwargs) return "hhhhh" ret = test1(100) print(ret) # ===================结果================ ----开始装饰权限2的功能---- ---开始装饰权限1的功能--- ----这是权限1---- ----这是权限2----- -----test1-----100 -----test1----- () -----test1----- {} hhhhh
装饰时,
@set_func1
想装饰,结果它发现下面的不是一个函数,然后它就去找,就开始执行@set_func2
,等@set_func2
装饰好时,相当于一个函数,这时@set_func1
就找到了它要装饰的东西,所以多个装饰器装饰同一个函数时,下面的装饰器先装饰- 一个小demo
# ===================结果================ def set_func_1(func): def call_func(): return "<h1>" + func() + "</h1>" return call_func def set_func_2(func): def call_func(): return "<a>" + func() + "</a>" return call_func @set_func_1 @set_func_2 def get_str(): return "hhh" print(get_str()) # ===================结果================ <h1><a>hhh</a></h1>
装饰器就把它理解成一个包装,一个装饰器相当于一层包装,外面的包装会把里面的那层包装给包住
-
带有参数的装饰器
def set_level(level_num): def set_func(func): def call_func(*args, **kwargs): if level_num == 1: print("----权限级别1,验证-----") elif level_num == 2: print("----权限级别2,验证-----") return func() return call_func return set_func @set_level(1) def test1(): print("-----test1----") return "ok" @set_level(2) def test2(): print("-----test2----") return "ok" ret = test1() print(ret) ret = test2() print(ret)
这个有点像把一个参数从外一层一层的传递进去,然后把最终结果一层一层的返回到原函数,有那么一点点…………绕。。
END…..