def f1(): print "f1" f1() #表示函數執行 f1 #表示函數,指向內存地址 f1 = lambda x: x + 1 f1() # 執行這個lambda表達式,而再也不是原來的f1函數,由於函數f1被從新定義了
假若有這麼一個需求,公司臨時規定將某塊業務加上訪問權限,由於代碼太多,又不想改變原有已經封裝好的
代碼,因而乎,基礎平臺的同志們想出了這麼一個解決辦法:利用裝飾器解決html
那麼什麼是裝飾器?這個問題先留着,直接看代碼:(代碼剖析:)python
def auth_login(func): # func = f1 ,func() = f1() def inner(): print "welcome to login ..." #驗證的內容加在這裏 func() # func() = f1() #至關於執行f1() reture inner # 返回 inner函數體 def f1(): #print "welcome to login ..." #需求是在這塊加上驗證(那麼怎麼實現?) print "f1..." result = auth_login(f1) #等於inner函數(包括它下面那一段代碼) f1 = result f1() #函數執行
基礎平臺代碼:(在業務平臺不須要修改調用方式的時候,直接調用基礎平臺這塊代碼)bash
bash.py #代碼名稱app
#!/usr/bin/env python #-*- coding:utf-8 -*- def auth_login(func): def inner(): print "auth user ..." # 認證模塊 func() return inner @auth_login #@auth_login 是python默認封裝好的一種方法,#至關於 result=auth_login(f1) # f1() = result()#(和上面的執行效果同樣) def f1(): print "I'm f1" def f2(): print "I'm f2" f1() #函數執行,這個是屬於業務部門來調用執行的,單獨拿出來調用,以下:
業務部門調用bash.py函數下的某個方法:函數
yw.py #業務程序名稱fetch
#!/usr/bin/env python #-*- coding:utf-8 -*- import bash bash.f1() #調用bash.f1 方法
執行業務程序 yw.py 結果以下:code
auth user ... I'm f1
顯然上面已經達到咱們的需求了,@auth_login 就是咱們的裝飾器,上面的列子就是對它使用的
其中一種方式;server
那麼問題來了:若是平臺須要再調用基礎平臺的 f2 方法,而且仍是帶參數的」傳入參數「的方法去調用,
顯然上面的程序已經再也不知足需求了;htm
那麼咱們能夠不能夠這麼作?就是咱們再另外定義另一個裝飾器,而這個裝飾器是能夠接受參數的;blog
bash.py #代碼名稱
def auth_login(func): def inner(): print "auth user ..." func() return inner def auth_arg_login(func): #這塊代碼是新加入的,傳入參數 def inner(arg): #參數 print "auth user arg ..." func(arg) return inner @auth_login def f1(): print "I'm f1" @auth_arg_login # 調用新裝飾器 def f2(arg): #參數 print "I'm f2",arg
業務部門再次調用bash.py函數下的方法:
yw.py #業務程序名稱
#!/usr/bin/env python #-*- coding:utf-8 -*- import bash base.f1() base.f2(」new programs") # 傳入參數
執行業務程序 yw.py 結果以下:
auth user ... I'm f1 auth user arg ... #這塊輸出 I'm f2 new programs #這塊輸出
這個時候,需求又變了,業務部門說,咱們須要傳遞2個參數,因而乎,基礎平臺啪啪啪,又寫了幾個方法,
又實現了,過了一段時間,業務平臺的同志來的時候說了一句話,兄弟,很差意思,我還須要傳遞幾個參數,
這個時候基礎平臺的同志發現本身快瘋了,CTO 老大看不下去了,這個時候,他告訴基礎平臺這麼一個方法,
也就是下面的代碼(傳遞動態參數)
bash.py #代碼名稱
#!/usr/bin/env python #-*- coding:utf-8 -*- def auth_login(func): def inner(*arg,**kwagrs): #動態參數 print "auth user ..." #認證模塊 func(*arg,**kwargs) #動態參數 return inner @auth_login #在函數上面加上這麼一句 @auth_login: 這個是python默認封裝好的一種方法, #至關於 result = auth_login(f1) # f1() = result() #(和上面的執行效果同樣) def f1(arg): print "I'm f1",arg
業務部門調用bash.py函數下的某個方法:
yw.py #業務程序名稱
#!/usr/bin/env python #-*- coding:utf-8 -*- import bash bash.f1('test') #調用bash.f1 方法
執行業務程序 yw.py 結果以下:
auth user ... I'm f1 test # 執行結果
1.裝飾器是一個函數 2. 執行auth_login 函數,被裝飾的函數做爲參數auth_login(f1) auth_login 函數的返回值, 賦值給被裝飾的函數的函數名 @auth_login def f1(): pass 3.動態參數,能夠裝飾含有n個參數的函數 4.函數返回值 5.多裝飾器 6.至少3層,3層的如何使用? @auth_login 1.執行auth_login函數 2.將auth_login函數的返回值給賦值給被裝飾器的函數的函數名 @auth_login(arg) 1.執行auth_login函數,獲得返回值,result 2.建立裝飾器,@ + result結合:@result 3... 1).執行result 函數 2).將result函數的返回值給被裝飾器的函數的函數名
bash.py #代碼名稱
def auth_login(func): def inner(*arg,**kwargs) print "welcome to login..." temp = func(*arg,**kwargs) print "login after..." return temp return inner @auth_login def fetch_server_list(): server_list = ['server1','server2','server3'] return server_list
執行業務程序 yw.py 結果以下:
import base server_list = base.fetch_server_list('test') print server_list
程序執行結果:
welcome to login... login after... ['server1', 'server2', 'server3']
上面的列子說了這麼多,好,如今咱們來作一個用戶登錄驗證:
def login(): # 這裏定義一個login 函數 name = "Allen" # 若是這裏是「Allen「,則下面的函數調用,驗證成功,不然失敗 if name == "Allen": return True else: return False def auth_login(func): def inner(*arg,**kwargs): is_login = login() #這裏加入一個驗證判斷 if not is_login: print "非法用戶" print "welcome to login..." temp = func(*arg,**kwargs) print "login after..." return temp return inner @auth_login def fetch_server_list(arg): server_list = ['server1','server2','server3'] return server_list
執行業務程序 yw.py 結果以下:
import base server_list = base.fetch_server_list('test') print server_list
welcome to login... login after... ['server1', 'server2', 'server3']
若是name = 」aaaa「, 不是」Allen「,則執行結果:驗證失敗:
非法用戶 welcome to login... login after... ['server1', 'server2', 'server3']
那麼又有人問,這個有個鳥用,我還須要密碼驗證,那麼這個怎麼作呢?
少廢話,直接上代碼:
def login(key): local_key = "123456" #這裏作個一個key驗證 if local_key == key: return True else: return False def auth_login(func): def inner(*arg,**kwargs): #key = kwargs['token'] #注意這裏 #del kwargs['token'] key = kwargs.pop('token') #這一句等於 上面註釋的兩句 #這句含義:由於下面的login 只接受一個參數,這裏多一個參數,全部刪除 is_login = login(key) #注意這裏 if not is_login: print "非法用戶" print "welcome to login..." temp = func(*arg,**kwargs) print "login after..." return temp return inner @auth_login def fetch_server_list(arg): server_list = ['server1','server2','server3'] return server_list
執行業務程序 yw.py 結果以下:
import base server_list = base.fetch_server_list('test',token=‘key1111’) #注意這裏 print server_list
@auth_login @auth_login def f1(): pass 執行的結果: 就是一層套一層
雙裝飾用途:
雙層裝飾器,能夠用在如下途徑: 好比用戶權限管理,第一層裝飾器用於用戶名密碼驗證, 第二層用在 判斷用戶是什麼身份的用戶,好比:普通用戶,超級用戶等
需求又來了,在上面獲取 fetch_server_list 以前執行一個函數,
可不能夠在fetch_server_list 以後再執行一個函數?
將以下三層裝飾器用語言解釋一遍:
#!/usr/bin/env python #coding:utf-8 def Before(request,kargs): print 'before' def After(request,kargs): print 'after' def Filter(before_func,after_func): def outer(main_func): def wrapper(request,kargs): before_result = before_func(request,kargs) if(before_result != None): return before_result; main_result = main_func(request,kargs) if(main_result != None): return main_result; after_result = after_func(request,kargs) if(after_result != None): return after_result; return wrapper return outer @Filter(Before, After) def Index(request,kargs): print 'index'
原文連接: http://www.cnblogs.com/yangyinghua/p/4987290.html