Python函數之裝飾器

裝飾器:本質是函數,功能是裝飾其他函數,就是為其他函數添加附加功能

編寫裝飾器的原則:

  • 不能修改被裝飾函數的源代碼
  • 不能修改被裝飾函數的調用方式

接下來模擬一個應用場景從頭編寫一個裝飾器:
有一個視頻網站有四個模塊:

def home():
    print("---首頁----")

def domestic():
    print("----國內專區(qū)----")

def america():
    print("----歐美專區(qū)----")

def japan():
    print("----日韓專區(qū)----")
 

視頻網站運營一段一時間后積攢了些客戶,現(xiàn)在要為歐美和日韓模塊進行收費,所以,調用該模塊時,需要判斷是否是付費vip會員。
通過之前的函數基礎知識的學習,輕易能想到的實現(xiàn)思路是:
單獨定義一個登陸函數,在調用歐美和日韓模塊時調用:

user_status = False #用戶登錄了就把這個改成True
 
def login():
    _username = "LZ" #假裝這是DB里存的用戶信息
    _password = "abc123" #假裝這是DB里存的用戶信息
    global user_status
 
    if user_status == False:
        username = input("user:")
        password = input("pasword:")
 
        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")
    else:
        print("用戶已登錄,驗證通過...")

def home():
    print("---首頁----")

def domestic():
    print("----國內專區(qū)----")

def america():
   login() #執(zhí)行前加上驗證
    print("----歐美專區(qū)----")

def japan():
   login() #執(zhí)行前加上驗證
    print("----日韓專區(qū)----")

 #調用模塊
home()
domestic()
america()
japan()

這樣就能完成需求。但是??!這違反了軟件開發(fā)中的一個原則“開放-封閉”原則,簡單來說,它規(guī)定已經實現(xiàn)的功能代碼不允許被修改,但可以被擴展:

開放——封閉

  • 封閉:已實現(xiàn)的功能代碼塊
  • 開放:對擴展開放

抱著不改變功能模塊源碼的想法我們會想到用高階函數,把模塊函數當參數傳入login()函數中:

user_status = False #用戶登錄了就把這個改成True
 
def login(func): #把要執(zhí)行的模塊從這里傳進來
    _username = "LZ" #假裝這是DB里存的用戶信息
    _password = "abc123" #假裝這是DB里存的用戶信息
    global user_status
 
    if user_status == False:
        username = input("user:")
        password = input("pasword:")
 
        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")
 
    if user_status == True:
        func() # 看這里看這里,只要驗證通過了,就調用相應功能
#原功能模塊不改
#調用模塊
home()
domestic()
login(america)
login(japan)

這樣,不改變功能模塊源碼也完成了需求,但是改變了調用方式!試想:每個模塊不同的人負責,這樣的話就得要求負責相應模塊的人都得去改調用方式。這。。。很危險啊。

現(xiàn)在在分析一下:之前函數基礎時講過函數也是變量,不改變函數調用方式的話,我們可以將login(america)賦值給america。但是有一個問題是當執(zhí)行america = login(america)代碼時,就已經把america執(zhí)行了啊!我們接下來要做的就是,當america = login(america)代碼時,返回一個函數,但是不執(zhí)行。等再調用america ()才執(zhí)行:

def login(func): #把要執(zhí)行的模塊從這里傳進來
 
    def inner():#再定義一層函數
        _username = "alex" #假裝這是DB里存的用戶信息
        _password = "abc!23" #假裝這是DB里存的用戶信息
        global user_status
 
        if user_status == False:
            username = input("user:")
            password = input("pasword:")
 
            if username == _username and password == _password:
                print("welcome login....")
                user_status = True
            else:
                print("wrong username or password!")
 
        if user_status == True:
            func() # 看這里看這里,只要驗證通過了,就調用相應功能
 
    return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()才會執(zhí)行inner函數

這樣當調用時先america = login(america)你在這里相當于把america這個函數替換了,然后在調用america ()。Python中提供語法在要被裝飾的函數前寫@login就相當于america = login(america)。所以調用時:

 #調用模塊
home()
domestic()
@login
america()
@login
japan()

執(zhí)行完america = login(america)之后,america就相當于調用的時inner.所以,如果原來的america如果有參數的話,在inner函數上添加參數即可:

def login(func): #把要執(zhí)行的模塊從這里傳進來
 
    def inner(*args):#再定義一層函數
        _username = "alex" #假裝這是DB里存的用戶信息
        _password = "abc!23" #假裝這是DB里存的用戶信息
        global user_status
 
        if user_status == False:
            username = input("user:")
            password = input("pasword:")
 
            if username == _username and password == _password:
                print("welcome login....")
                user_status = True
            else:
                print("wrong username or password!")
 
        if user_status == True:
            func() # 看這里看這里,只要驗證通過了,就調用相應功能
 
    return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()才會執(zhí)行inner函數

#調用

@login
america('jack')

寫到這,login就是一個裝飾器了。它是一個函數,只是給原來的函數增加了驗證功能。既沒有改變原函數代碼,也沒有改變調用方式!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,932評論 25 709
  • 有時候我們想為多個函數,同意添加某一種功能,比如及時統(tǒng)計,記錄日志,緩存運算結果等等,而又不想改變函數代碼那就定義...
    ketchup閱讀 3,139評論 0 3
  • 如果我想念一個朋友,我想念的到底是什么。 是她或他的一個習慣,是她或他的一個品質。 最近巧合地延續(xù)了一個多年前朋友...
    細雨薔薇閱讀 210評論 0 0
  • 前言碎語 前陣子上映的電影《喜歡你》,是一部以美食和愛情為主題的電影。在看影評時,有一段描述寫的特別好: “笑到累...
    一池YiCHi閱讀 467評論 0 1

友情鏈接更多精彩內容