python裝飾器進階

来源:https://www.cnblogs.com/failymao/archive/2019/03/01/10454240.html
-Advertisement-
Play Games

[TOC] 裝飾器進階 通過上一篇已經知道, 如果還有概念還不理解的請返回裝飾器入門 "裝飾器入門" 裝飾器 實際也是一種函數, 他是 python語言的重要組成部分, 在實際開發中應用也相當廣泛. 正如我們所知, 前面所看到的被裝飾的函數都是最簡單函數格式, 這裡所說的簡單, 是指 ,`或者函數沒 ...


目錄

裝飾器進階

通過上一篇已經知道, 如果還有概念還不理解的請返回裝飾器入門裝飾器入門裝飾器 decorator實際也是一種函數, 他是 python語言的重要組成部分, 在實際開發中應用也相當廣泛. 正如我們所知, 前面所看到的被裝飾的函數都是最簡單函數格式, 這裡所說的簡單, 是指 函數無參數的形式,或者函數沒有返回(直接執行結果)值在實際開發中我們遇到更多的其實是擁有多個參數`,那麼這種裝飾器該如何編寫?

被裝飾的函數有參數

  • 實例代碼

    from functools import wraps
    
    def auth2(func):
        @wraps(func)
        def wrapper(*arg, **kwargs):
            user = input("pls input password:").strip()
            if user == "faily":
                print("---welcome login----")
                func(*arg, **kwargs)
          else:
              print("----wrong password----")
      return wrapper
    
    @auth2
    def task2(name, is_happy="Yes"):
                    print("{0} is doing somthing, Is he happy? [{1}]".format(name, is_happy))
    
    
    if __name__ =="__main__":
         '''帶參數的裝飾器'''
         task2("faily")

    可以看出,被裝飾的函數task2 擁有兩個參數,name, is_happy, 那麼如何將兩個參數傳遞進裝飾器函數中呢?

  1. 根據前面我們所學的知識,可以看出, 裝飾器在執行的時候, 首先將被裝飾的 函數名 這裡是task2傳遞給裝飾器函數 auth2, 那麼被裝飾函數的參數 就不得不找別的地方傳進去, 唯一可以接受這些變數的地方就是 wrapper函數.
  2. 通過wrapper 函數將參數傳進去之後呢, 再建參數傳遞個 被裝飾的函數 即可

被裝飾的函數有返回值

  • 顯然 這種函數最普遍, 函數在執行後立即展示結果,而是作為值進行傳遞

    from functools import wraps
    
    def auth3(func):
    
      @wraps(func)
        def wrapper(arg):
            user = input("pls input password:").strip()
            if user == "faily":
                print("---welcome login----")
                return func(arg)
            else:
                print("----wrong password---")
    
        return wrapper
    
    @auth3
    def task3(name):
        print("do somthing ")
        return name
    
    if __name__ == "__main__":
        ts = task3("momo")
        print(ts)

    這種很好理解, 函數有返回值, 那麼在wrapper函數內執行完新加功能後, 直接return 被裝飾的函數即可

在函數中嵌入裝飾器

在這裡我們可以這樣理解: 既然裝飾器是高階函數 + 嵌套函數 = 裝飾器 那麼可不可 有這種組合呢,即 裝飾器 + 嵌套函數的形式呢?

答案是肯定的

其實這種應用也可理解為. 之前我們寫的所有裝飾器都是自己不帶參數的, 有沒有想過 帶有參數的 裝飾器該如何實現呢?

  • 回到日誌的例子,並創建一個包裹函數,能讓我們指定一個用於輸出的日誌文件

    from functools import wraps
    
    def logit(logfile='out.log'):
    
        # 裝飾器 
        def logging_decorator(func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打開logfile,並寫入內容
                with open(logfile, 'a') as f:
                    # 現在將日誌打到指定的logfile
                    f.write(log_string + '\n')
                return func(*args, **kwargs)
            return wrapped_function
        return logging_decorator
    
    #預設裝飾器參數
    @logit()
    def myfunc1(action="run"):
        if action == "run":
            return True
        else:
            return False
    
    #裝飾器傳參
    @logit(logfile='func2.log')
    def myfunc2(action = "stop"):
        if action == "run":
            return True
        else:
            return False
    
    if __name__ == "__main__":
      myfunc1()
      myfunc2()
    
    # 現在一個叫做 func2.log 的文件出現了,裡面的內容就是上面的字元串 

    這個例子中, 是不是決定裝飾器實在是太強大了, 我們可以通過為裝飾器給予不同的參數實現不同函數日誌輸出的新增功能, 我們只是在標準裝飾器外外加了一層函數,這個函數實際就是為了用來將裝飾器的參數傳遞進包裹函數中.

裝飾器類

場景分析 : 在運維監控中, 我們常常需要記錄不同級別,或者不同app產生的日誌,但當我們的應用程式的某些部分還比較脆弱時,觸發異常也許是需要更加關註的事情. 比方說有時只想記錄日誌到一個文件; 而有時你想在程式發生異常時送到一個email,同時也保留日誌。這是一個使用繼承的場景,但目前為止我們只看到過用來構建裝飾器的函數。

幸運的是,類也可以用來構建裝飾器。那我們現在以一個類而不是一個函數的方式,來重新構建logit

  • 裝飾器類

    rom functools import wraps
    
    class logit(object):
        '''裝飾器類'''
        def __init__(self, logfile='out.log'):
            self.logfile = logfile
    
        def __call__(self, func): # __call__說明這是一個callable
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打開logfile並寫入
                with open(self.logfile, 'a') as f:
                    # 現在將日誌打到指定的文件
                    f.write(log_string + '\n')
                # 現在,發送一個通知
                self.notify()
                return func(*args, **kwargs)
            return wrapped_function
    
        def notify(self):
            # logit只打日誌,不做別的
            pass

    這個實現有一個附加優勢,在於比嵌套函數的方式更加整潔,而且包裹一個函數還是使用跟以前一樣的語法:

    @logit()
    def myfunc1():
        pass

    現在,我們給logit創建子類,來添加email的功能。

    class email_logit(logit):
        '''
        一個logit的實現版本,可以在函數調用時發送email給管理員
        '''
        def __init__(self, email='[email protected]', *args, **kwargs):
            self.email = email
            super(email_logit, self).__init__(*args, **kwargs) # 集成父類
    
        def notify(self):
            # 發送一封email到self.email
            # 這裡就不做實現了
            pass

    從現在起,@email_logit將會和@logit產生同樣的效果,但是在輸出日誌的基礎上,還會多發送一封郵件給管理員。

總結

裝飾器進階已經講完, 下一篇我們繼續研究, 多重裝飾器


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現在構建任何類型的軟體項目最流行的方法這是使用類。在這篇文章中,探討用 JavaScript 實現類的不同方法,以及如何構建類的結構。首先從深入研究原型工作原理,並分析在流行庫中模擬基於類的繼承的方法。 接下來是講如何將新的語法轉製為瀏覽器識別的語法,以及在 Babel 和 TypeScript 中 ...
  • 使用CSS3實現動畫勾選 相信大家在項目中會經常遇到這種需求:勾選框。現在用CSS3來實現一個動畫勾選,只需要一個標簽即可完成: 這次需要用到CSS中偽類 after,這個小技巧也是很容易忘記的,所以決定記錄起來~ 首先給標簽加寬高加背景色: 接下來利用偽類給標簽添加元素,同時水平垂直居中: 變成這 ...
  • 1、首先要安裝nodejs和npm。 下載nodejs安裝,下載地址:https://nodejs.org/en/ 安裝很簡單一路next即可。 安裝完成後可以在cmd視窗輸入node -v 和 npm -v 查看是否安裝成功 2、vue-cli腳手架安裝 CMD命令行輸入:npm install ...
  • sudo -s npm install -g yarn react-native-cli ...
  • 今天碰到的一個比較煩人的問題是,在body上添加事件處理函數,發現在iphone上怎麼也沒辦法觸發事件,找了半天,發現iPhone處理冒泡事件的規則: 1.點擊某個元素; 2.如果這個元素上沒有處理該事件,則繼續向上冒泡,直到body下的子節點為止。如果此時還是沒有元素處理這個事件,則丟棄該事件,不 ...
  • 如果你是一個人在自學前端開發,或者是對前端開發有比較濃厚的興趣正想踏入前端領域,只要你在前端自學路上遇到了自己無法解決的技術難題,那麼儘管將你的疑惑交給我的小伙伴兒們吧,我們都是一群在前端自學路上摸爬滾打的有志青年,希望你可以來和我們共同交流。同時也希望你能獻出自己的一份力,幫助我的小伙伴兒們解決他 ...
  • 原型與原型鏈 javascript 創建對象 類與構造函數是大多數編程語言所擁有的,而借鑒了 C 與 JAVA 的 javascript 也是有類和構造函數的,不過 javascript 的實現不太一樣。 上面的例子中, 就是構造函數, 就是它的實例,但是它對共用性不太好,所以有了原型模式。 原型模 ...
  • 這兩天接觸到一個很有意思的 CSS 屬性 -- box-decoration-break。下麵就一起去一探究竟。 因為 MDN 上關於這個屬性,沒有中文文檔,所以一直在想一個合理貼切的中文翻譯。直譯一下: box -- 盒,可以理解為元素盒模型 decoration -- 裝飾,理解為元素樣式 br ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...