python 中一切皆对象,变量是对象,函数也是对象
def funcName():
return 1
f = funcName #funcName 是一个函数名,也是一个对象的名字,所以也可以赋值给一个变量,将对象funcName赋值给变量f
f() # 通过变量f来实现函数funcName函数的调用执行,f()=funcName()
装饰器本质上也是一个函数,作用是可以不修改原有代码的基础上去扩展现有函数功能。它的原理就是讲原函数对象作为参数传递给装饰器函数,并且返回这个原函数执行的结果。这个过程就是装饰器的装饰过程。而我们会
首先我们先看一个简单的例子:假如,我们有2个部门,一个是开发部门,这个功能的技术模块由开发部门提供(也就是说,home ,tv ,movie 这些功能模块的搭建由开发部门建立),
还有一个是运维部门。他们赋值调用这些基础平台的功能(home,tv,moive函数),home,tv,moive 调用,是他们执行调用。)
开发人员搭建的三个功能模块:
def home():
res = print("welcome to my home page")
return res
def tv():
res = print("welcome to my tv page")
return res
def movie():
res = print("welcome to my movie page")
return res
运维部门同事调用三个功能模块:
home() # 调用并执行home函数
tv() # 调用并执行tv函数
moive() 调用并执行movi函数
运行代码且返回的结果是:
"welcome to my home page"
"welcome to my tv page"
"welcome to my movie page"
这是已经定义好的功能模块,三个函数,一个home ,一个tv ,一个是moive ,需求来了,要给这三个函数加个验证登录的功能。怎么办?
我们先看看,有什么较好的办法实现这个需求功能。在执行home,tv,moive函数之前,我需要先验证。这个验证功能函数如果写呢?
def login(func):
print("Verify, you can accss my web site")
return func
def home():
res = print("welcome to my home page")
return res
def tv():
res = print("welcome to my tv page")
return res
def movie():
res = print("welcome to my movie page")
return res
运维人员需要使用上面的功能模块,就会执行下面的代码调用:
home = login(home) # 把home 函数作为参数传递给login 并且,login 执行调用了login(),注意,返回这个参数是的函数
home()
tv = login(tv)
tv()
moive = login(moive)
moive()
执行这个代码,返回的结果是:
"Verify, you can accss my web site"
"welcome to my home page"
"Verify, you can accss my web site"
"welcome to my tv page"
"Verify, you can accss my web site"
"welcome to my movie page"
注意:home = login(home) 只要函数带了括号,就会被执行。所以login 函数会执行,home 函数没有带括号只是作为要给参数传递给login ,将login 的执行结果赋值给给这个参数函数 。
上面的代码虽然可以满足user 的需求,没有太多修改现有代码的地方,但是你想想,如果你是运维部门,开发人员提供好了home ,tv ,moive 功能模块,也增加了login 模块,而你需要去调用你的这些函数功能模块,他们在调用调用home,tv,moive 前,都需要先加上:home = login(home),tv = login(tv),moive = login(moive),虽然改动不是很大,但是依然让你修改了现有的代码,你是不是会对开发人员很大的抱怨,虽然,只是每次调用前加上一句代码。
那么我们又什么更好的方法去解决这个问题了,不修改现有代码的基础上。只是扩展了新的功能模块,这就是我们接下来要介绍了的重点-装饰器。
接下来我们就看看有了装饰器,如果去定义一个login的装饰器,且在现有的功能以及使用这个装饰器。因为装饰器本身也是一个函数,所以我接下来就去定义这个装饰器函数。
1 不带参数的函数的功能模块的扩展:
def login(func): # func 是原函数对象(包含home函数对象/tv函数对象/movie函数对象)作为参数传递给装饰函数login,然后返回这个原函数执行的结果
def inner():
print("Verify,you can access it")
return func()
return inner
@login
def home():
res = print("welcome to my home page")
return res
@login
def tv():
res = print("welcome to my tv page")
return res
@login
def movie():
res = print("welcome to my movie page")
return res
运维人员需要使用上面的功能模块,就会执行下面的代码调用:
home()
tv()
moive()
2 带不确定参数的(动态参数)函数的装饰器原函数不确定带几个参数的装饰器
def login(func): # 将函数对象作为参数传递给装饰器函数login
def inner(*args,**kwargs): # 装饰内嵌函数
print("Verify you can access it") #新功能函数被包含在装饰器内嵌函数里
return func(*args,**kwargs) #返回原函数对象执行结果,带参数
return inner #返回装饰内嵌函数对象
@login
def home():
res = print("welcome to my home page")
return res
@login
def tv(name,password):
res = print("welcome %s to my tv page" %name)
return res
@login
def movie(name,id):
res = print("welcome %s and %d to my movie page" %(name,id))
return res
基本上掌握上述2种装饰器的用法,能解决大部分的问题。
前面两种都是函数带参数或带动态参数的装饰器的用法,接下来,我们最后介绍装饰器自己带参数的用法,但是它用在什么样的场景呢?例如login进行验证的函数功能,它有很多种验证方式,有账号密码的验证,有LDAP 验证,有AD 验证,有key 的认证等等,运维部门需要什么的验证,就去调用什么的login ,这个我们就可以利用带参数的装饰器来完成。
def loginmaker(*args,**kwargs): # 把装饰器login再包一层
def login(func):
def inner(*args,**kwargs):
print("Verfiy you can use it ")
return func()
return inner
return login #返回这个装饰器对象
@loginmaker("calda\bjdong","123445") # ad 的认证
def home():
res = print("welcom you to my home page")
return res
@loginmaker("daofnda8823ndfafdafds_$ferae") # key 认证
def tv(name,password):
res = print("welcome %s to my tv page")
@loginmaker("joice","1234455") # 账号认证
def moive(nickname,id):
res = print("welcome %s your id is %d" %(nickname,id))
home()
tv()
movie()