python:裝飾器

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>

待續。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章