Python基础知识:5:装饰器

来源:互联网 发布:老虎机的算法原理 编辑:程序博客网 时间:2024/05/29 19:50

    装饰器的作用就是为已经存在的对象添加额外的功能。

    基于开放封闭原则,在不改变调用者的前提下,在调用之前或之后增加一些功能;

    当你有100个或更多的调用程序需要同时增加/修改同一个内容时,使用装饰器会非常有用;


案例1:假设100个程序都要同时额外增加一个功能,如在执行程序前打印字符log;

    一种实现方式是:把这个功能复制到100个程序中,但缺点是无法灵活控制outer和f的先后执行顺序,且修改起来很麻烦,需要一个程序一个程序的去修改。

    这时,就需要一个装饰器来封装一个功能。

#定义装饰器
def outer():#定义在常规程序外的函数outer,作用是打印log
   
print('log')
#使用装饰器
def f1():
outer()#使用装饰器
 
print('F1')
def f2():
outer()
print('F2')
def f100():
outer()
print('F100')
#执行程序
print('f1执行效果:')
f1()
print('f2执行效果:')
f2()
print('f100执行效果:')
f100()

执行结果:

要理解装饰器,必须要先理解函数,具体可参考另外篇博文。

函数两个基本知识:

1)函数的执行从上往下,后一个变量/函数会覆盖前一个变量/参数。

def f1():
print(123)

def f1():
print(456)
f1()

#因为执行顺序为从上到下,因此后一个f1会覆盖前一个f1,执行结果为456


函数的执行顺序案例:

2)函数是可以作为整体进行传递的;如果传递的为函数名,而又没有加(),则函数是作为整体去传递

#先将f1作为整体传递给f2的xxx,再执行f2中的函数体,因为f2的函数体xxx(),因此,继续执行f1()
def f1():
print("函数1执行",123)

def f2(xxx):
print("函数2执行",456)
xxx()#会去执行f1()
f2(f1)#将f1传递给xxx,则xxx=f1

执行结果:


装饰器@+函数名,有两大功能:

1)自动执行outer函数,且将其下面装饰的函数名f1当做参数传递给装饰器中的参数;

2)将outer函数的返回值重新赋值给f1


案例2:解释装饰器的工作原理:在装饰器中无其他的函数

案例2-1:无装饰器案例:执行f1()

1)存储返回值

def f1():
print('F1')
return 123#f1有返回值123
f1() #执行f1函数体,执行结果为F1

执行结果:

2)不存储返回值

def f1():
print('F1')
return 123#f1有返回值123
r=f1() #执行f1函数体,并将f1的返回值赋值给r
print(r)#因f1的函数体有返回值,为123,直接打印123

执行结果:


案例2-2:加入装饰器后:执行f1(),会修改原有的f1函数体,而原有的函数体不再被执行

案例解读:

  • 函数从上到下执行,在执行def f1()时,发现其上面的装饰器,会把装饰器下的f1作为参数传递给装饰器,代替装饰器中的参数func

  • f1的函数体,将不会被执行,比如:print('F1')就不会出现

  • 装饰器执行后的返回值111,重新赋值给f1,因此f1目前的值为111

  • 执行f1(),就是执行111(),就会出错

1)因为装饰器的返回值为111,而执行f1即执行111(),这个就会出错了
def
outer(func):
return "111"
@outer#装饰器
def f1():
print('F1')
return "123"#f1有返回值123
f1()#因f1已经被重新赋值了111,执行f1()即执行111(),因此再执行是就会出错

执行结果:出错的执行结果

2)可以看下f1此时的值;执行结果为111
def
outer(func):
return "111"
@outer#装饰器
def f1():
print('F1')
return "123"#f1有返回值123
print(f1)#因f1已经被重新赋值111


案例3:解释装饰器的工作原理:装饰器中内置函数,暂无参数func

案例3-1:装饰器下的函数会传递给装饰器的参数

    案例解读:执行装饰器,把f1赋值给func,定义inner函数;装饰器的返回值为inner函数,赋值给f1,此时再执行f1()时,即为执行inner(),结果为"打印inner函数"

#装饰器中有函数
def outer(func):#func为老的f1
   
def inner():#定义inner,下面inner的函数体
       
print("执行inner函数体")
return inner #inner代指inner函数的函数体,并将这个函数体赋值为f1

@outer
def f1():
print('执行f1函数体')
return "123"#f1有返回值123
f1()#f1已被重新赋值为inner,因此当执行f1()时,即执行inner()

执行结果:


案例4:解释装饰器的工作原理:装饰器中内置函数,且有参数func。

因f1会被替换成装饰器的返回值,因此,装饰的参数func指的老的f1,新的f1为inner,内层函数无返回值的情况

1)先打印字符log,再执行程序

def outer(func):#func为原有的f1
   def inner(): #定义inner函数
        print('inner函数:log')
func()#因func代指原来的f1,因此执行原有的f1函数体
   return inner#此为装饰器的返回值,被赋值为f1

@outer
def f1():
print('执行f1函数体')
return "123"#f1有返回值123
f1()#即执行装饰器中的inner函数

执行结果:

2)先打印字符log,再执行程序,再打印after:

def outer(func):#func为原有的f1
   def inner(): #定义inner函数
       print('inner函数:log')
func()#因func代指原来的f1,因此执行原有的f1函数体
       print('after')
return inner#此为装饰器的返回值,被赋值为f1

@outer
def f1():
print('执行f1函数体')
return "123"#f1有返回值123
f1()#即执行装饰器中的inner函数

执行结果:

案例5:装饰器内层函数有返回值

先打印字符log,再执行程序,同时取旧程序的返回值,再打印after:

def outer(func):#func为原有的f1
   def inner(): #定义inner函数
       print('inner函数:log')
r=func()#因func代指原来的f1,因此执行原有的f1函数体,并将旧f1的返回值传递r,即r="f1的返回值123"
       print('after')
return r #inner函数最后返回值为人,函数遇到return,下面就不执行了
   return inner#此为装饰器的返回值,被赋值为f1

@outer
def f1():
print('执行f1的函数体')
return "f1的返回值123"#f1有返回值123
r=f1()#即执行装饰器中的inner函数,并取inner函数的返回值,即r
print(r)

执行结果:


此处可以总结下装饰器的执行顺序:


案例6和案例7讲解内部函数有参数的情况:

案例6:装饰器中的参数:当f1有参数时,装饰器中也需要输入参数

def outer(func):#func为原有的f1
   
def inner(a): #定义inner函数
       
print('inner函数:log')
r=func(a)#因func代指原来的f1,因此执行原有的f1函数体,并将旧f1的返回值传递r,即r="f1的返回值123"
       
print('after')
return r #inner函数最后返回值为人,函数遇到return,下面就不执行了
   
return inner#此为装饰器的返回值,被赋值为f1

@outer
def f1(arg):
print(arg)
return "f1的返回值123"#f1有返回值123
r=f1("f1需要加入参数")#需要传递参数
print(r)

执行结果:


案例7:装饰器中的参数:f1...f100的参数个数不一致时,需要使用动态参数

def outer(func):#func为原有的f1
   def inner(*args,**kwargs): #定义inner函数,使用动态参数
       print('inner函数:log')
r=func(*args,**kwargs)#因func代指原来的f1,因此执行原有的f1函数体,并将旧f1的返回值传递r,即r="f1的返回值123"
       print('after')
return r #inner函数最后返回值为人,函数遇到return,下面就不执行了
   return inner#此为装饰器的返回值,被赋值为f1

@outer
def f1(arg):
print(arg)
return "f1的返回值123"#f1有返回值123
@outer
def f2(arg1,arg2):
print(arg1,arg2)
return "f2的返回值456"#f1有返回值123

r1=f1('f1传递1个参数')
print(r1)
print('--------执行传递俩参数案例--------')
r2=f2("f2传递参数1","f2传递参数2")
print(r2)
执行结果:


案例链接:https://pan.baidu.com/s/1dFvrRS9 密码:27cj






原创粉丝点击