python之路第五篇之裝飾器(進階篇)

裝飾器:

學前必備知識:

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函數的返回值給被裝飾器的函數的函數名
裝飾器返回值(return):
獲取主機列表:

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 以後再執行一個函數?

做業1:

將以下三層裝飾器用語言解釋一遍:

#!/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

相關文章
相關標籤/搜索