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 num
f1(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" % num
print 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" % num
print 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=None
def wrapper(*args,**kwargs):
return "<"+tag+" "+css_class+">"+main_fun(*args,**kwargs)+"</"+tag+">"
return wrapper
return 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>
待續。。。。