python装饰器原理

装饰器:遵循开放封闭原则,给已存在的功能,添加新功能。
首先:例如 函数login的函数名只是一个内存地址,函数login()才是执行函数

def login(func):
  print("已经通过验证")
  return func

@login #装饰器,将主函数作为参数传入login函数。
def play(name):
  print("欢迎 {%s} 进入游戏" % name)

#play = login(play) 等价于 @login #装饰器原理
play('li')

程序过程(不完整的装饰器原理):
1:python解释器将从上往下读入代码,先将login读入到内存,但没有执行。因为没有login()
2:读到@login,python会先运行装饰器的函数名的函数,并将主函数的地址值作为参数,

传入函数体内(主函数现在相当于变成一个局部变量),所以该函数会打印print("已经通过验证"),

然后return func返回主函数的函数名的地址值。play = login(play),主函数被覆盖。

缺点:不调用新play该函数仍然会打印print("已经通过验证")

 

完整的装饰器

将login函数不执行,返回主函数

def login(func):
  def inner(arg):
    print("已经通过验证")
    func(arg)
  return inner
@login     # 相当于play = inner  即原play函数被覆盖了
def play(name):
  print("欢迎 {%s} 进入游戏" % name)
play('li')

程序过程(装饰器的原理):
1:python解释器将从上往下读入代码,先将login读入到内存,但没有执行。因为没有login()
2:读到@login,python会先运行装饰器名的函数,并将主函数(装饰器装饰的函数)的地址值作为参数,

传入装饰函数体内(主函数现在相当于变成一个局部变量),所以login函数会return inner返回inner函数的函数名的地址值。

该步相当于play = inner inner函数没有执行只是传了inner函数的地址值
3:读到play(‘li’)时候,相当于inner(‘li’),因为inner(‘li’)相当于执行函数inner并将’li’字符串作为参数传入inner函数,
4:inner(‘li’)函数开始执行,打印print("已经通过验证"),并通过局部变量func的地址值,开始执行func(arg)即执行func(‘li’),

func的地址值就是play,所以就相当于运行了play(‘li’)。该函数实现了执行play(‘li’)前,先执行验证。

 

带参数的装饰器(高级理解)

def Login(name):
  print("欢迎 %s 登录游戏!!!" % name)
def Logout(name):
  print("再见 %s,生活愉快!!!" % name)
def zsc(Login,Logout):
  def zs(func):
    def inner(arg):
      Login(arg)
      func(arg)
      Logout(arg)
    return inner
  return zs
@zsc(Login,Logout)
def play(name):
  print("%s正在玩游戏" % name)
play('li')

程序运行:
1:python读入Login,Logout,zsc三个函数,然后读入@zsc(Login,Logout),这里注意:python对于函数()是代表开始运行函数,

而不是读入内存,所以这里开始会先运行函数zsc(Login,Logout),返回了函数zs的函数地址值(注意是没有运行的)。
2:所以装饰器变成@zs了,python会先运行装饰器名的函数,并将主函数(装饰器装饰的函数)的地址值作为参数,传入装饰函数体内(主函数现在相当于变成一个局部变量),即执行zs(play)函数,该函数返回了inner函数的地址值(注意这里也没有执行inner函数),所以play(‘li‘)即为inner(‘li’),
所以结果
欢迎 li 登录游戏!!! (代表添加主函数运行前添加的功能)
li正在玩游戏 (代表主函数运行)
再见 li,生活愉快!!! (代表添加主函数运行后添加的功能)

 
posted @ 2017-06-29 17:39  zimsan  阅读(180)  评论(0)    收藏  举报