10.31 Python装饰器
需要了解装饰器,需要先了解闭包,装饰器中有用到闭包
装饰器就是在不修改函数代码的前提下修改添加函数功能
闭包和装饰器在开发和面试中必问的,常用的
1.闭包
闭包就是多层函数嵌套定义,往往内部函数用到外部函数的变量,把这个整体当作一个特殊的对象
如果在一个内部函数里对外部作用域(但不是全局作用域)的变量进行引用,内部函数称为闭包(closure)
1.1闭包引用
call()方法 创建的实例对象,对对象()执行这个方法
函数里再定义函数返回函数
因为python里都是对象,都是引用
面向对象好处,类之间相互隔离,变量方法分开空间存放,安全。包就和闭包一样
函数:能把代码封装
匿名函数:能完成小部分编写,传实参
闭包:只传一部分数据,拥有函数的功能,还能传一部分数据
类:传过去什么都有
def line(k,b)
def create_y(x)
print(k*x+b)
return create_y #不能加括号,因为返回的是引用函数,而不是函数里的值
line_1 = line(1, 2)
line_1(1)
作为补充:什么是匿名函数:
所谓匿名就是不需要函数表达式
lambda x : x*x
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
1.2闭包修改外部函数变量
类似修改全局变量的global,闭包外边的变量加上nonlocal
2.装饰器
装饰器是程序开发的基础知识,做python开发必须要会
函数是一个引用;
开放封闭原则:
对已实现的功能代码块封闭!
对扩展开放!;
这里就用到装饰器了
定义一个闭包,@闭包名,就是装饰器
如果调用装饰器修饰函数,会先加载对应装饰器;
所以说是可以做到在不修改函数代码的前提下,修改函数的功能;
def set_func(func):
def call_func():
print('权限验证1')
print('权限验证2')
func()
return call_func()
@set_func
def test1():
pass
test1()
2.1装饰器的实现过程:
加装饰器调用test1()相当于
不加装饰器:
test1 = set_func(test)
test1()
会先验证闭包
test1指向内部函数
@这个符号我们就称为语法糖?
23中程序设计模式,其中就有装饰器模式
2.2对有参数函数和无参数函数的修饰
2.2.1 无返回值无参数的最简单
无返回值有参数:
def set_func(func):
def call_func(num):
print('权限验证1')
print('权限验证2')
func(num)
return call_func()
@set_func
def test1(num):
pass
test1(100)
如果有参数,那么闭包里的内部函数也要有形参,内部函数里面的函数调用也要有形参
注意:
同一个装饰器可以对多个函数装饰器,每装饰一个就创建一个闭包。只要写了语法糖?,没有调用函数之前就调用闭包,调用装饰器了
2.2.2 不定长参数函数的装饰
同样的,内部函数形参都换成不定长参数args,**kwargs,内部的引用函数也加上args,**kwargs
def set_func(func):
def call_func(*args,**kwargs):
print('权限验证1')
print('权限验证2')
func(*args,**kwargs)
return call_func()
@set_func
def test1(num,*args,**kwargs):
pass
test1(100,200,300,mm=100)
2.2.3 有参数,有返回值
def set_func(func):
def call_func(*args,**kwargs):
print('权限验证1')
print('权限验证2')
return func(*args,**kwargs)
return call_func()
@set_func
def test1(num,*args,**kwargs):
return 'ok'
ret = test1(100,200,300,mm=100)
print(ret)
这个就是通用装饰器,就算没有返回值也不会报错,因为没有返回值会返回None
2.2.4 多个装饰器对同一个函数装饰
多个装饰器可以对同一个函数装饰,就是经过装饰器的层层过滤;
如果多个装饰了,先装饰离被装饰函数近的,就是下面的再装饰上面的,执行反过来,先执行上面的再执行下面的
demo:
def set_fun_1(func):
def call_func():
return '<h1>'+func()+'</h1>'
return call_func
def set_fun_2(func):
def call_func():
return '<tb>'+func()+'</tb>'
return call_func
@set_fun_1
@set_fun_2
def get_str():
return 'haha'
print(get_str())
>>>>>> <h1><tb>haha</tb></h1>
2.2.5带参数的装饰器
定义三个函数嵌套,因为原来最外层的函数参数已经接收了被装饰函数的函数名,所以在外面再定义一个函数,这样完成了带参数的装饰器
2.2.6 类装饰器
类装饰器可以装饰函数也可以装饰类
这个用的很少,不写了