1.情景引入。
现在已经完成了一个python项目,但是我们为了安全起见,我们需要加入验证机制。不是所有人都能调用函数
原始源代码
def f1():print 'f1'def f2():print 'f2'def f3():print 'f3'
由于必须遵循开发闭包的原则,所以我们应该尽可能的是不去改动原来函数的内部代码,而是通过其他的一些方法添加新的功能
比如通过下面这样的方法
#首先定义一个验证函数,参数为一个函数
def verification(func):print("verification success!!!")return func #返回传入函数的首地址def f1():print 'f1'def f2():print 'f2'def f3():print 'f3'f1=verification(f1)
#执行这一句代码后,会直接输出"verification success!!!",因为我们执行了verification这个函数。然后返回传入函数的地址
#再执行返回的函数,这样就会执行f1()这个函数
f1()
#最终结果
"""
verification success
f1
"""
换一种写法,实现和上面同样的功能——–装饰器
def verification(func):print("verification success!!!")return func #返回传入函数的首地址@verification
def f1():print 'f1'
@verification跟上一段代码的f1=verification(f1)这条语句等价,此时的f1已经是verification函数的返回值了,即func
上面的代码不经过任何调用直接运行
结果:
verification success!!!
加一条代码
f1=f1() #相当于f1=func(),func是verification返回的函数,即原f1()函数结果:
verification success
f1
由此我们发现了一个问题,那就是我们直接使用@verification的时候他是直接执行了verification这个函数,因此他会先有输出”verification success“,这就出现了不统一的问题,按照我们原来的设想是”verification success“和”f1“应该同时输出的。因此我们用相同的原理,写一个内部函数,通过返回内部函数的地址,达到不执行函数的效果
代码如下:
def verification(func):def inner():print "verification success"func()return inner #返回了一个函数的地址,没有直接执行@verification
def f3():print 'f3'
此时函数f3已经变成了inner了,然后我们调用f3,即inner
f3() #这里就直接执行了inner函数
输出结果
verification success
f1
实现(原函数无返回值)
def verification(func):def inner(arg):if arg>100:func(arg)else:print "verification fail"return inner@verification
def f1(num):print num@verification
def f2(num):print numf1(101)
f2(88)
结果:
101
verification fail
原函数有返回值
def verification(func):def inner(arg):if arg>100:return func(arg)else:return "verification fail"return inner@verification
def f1(num):return "data is %d"%num@verification
def f2(num):return "data is %d" % numprint f1(101)
print f2(88)结果:
data is 101
verification fail
多参数传递
"验证功能的函数"
def verification(func):def inner(*args,**kargs):if 'password' in kargs:password=kargs['password']else:password='000'if password=='233':return func(*args)else:return "verification fail"return inner@verification
def f1(num):return "data is %d"%(num)@verification
def f2(num):return "data is %d" % numprint f1(101,password='233') #此时的f1其是inner函数
print f2(88)#结果:
data is 101
verification fail
2.装饰器
就如同以上代码一样,想要对一个已有的模块做一些“修饰工作”,所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去。
3.进阶版—-带参数Decrorator
def makeHtml(tag,*args,**kwargs):def realDeco(main_fun):if 'css_class' in kwargs:css_class="class={}".format(kwargs['css_class'])else:css_class=Nonedef wrapper(*args,**kwargs):return "<"+tag+" "+css_class+">"+main_fun(*args,**kwargs)+"</"+tag+">"return wrapperreturn realDeco@makeHtml(tag="b",css_class="bold_css")
def index():return 'hello world'print index()
执行过程
到@makeHtml时,程序执行过程
1.先执行makeHtml(tag=’b’,class=’bold_css’)函数,返回realDeco的地址
2.执行realDeco(index),获取到css_class变量的值,返回wrapper
3.执行print index().此时此刻的index=wrapper,执行wrapper()函数,
4.执行main_fun(即原index函数),重新拼接得到<b class=bold_css>hello world</b>
,最后返回了这个值
执行结果:
<b class=bold_css>hello world</b>
待续。。。。