6.0 Python 使用函數裝飾器

裝飾器可以使函數執行前和執行后分別執行其他的附加功能,這種在代碼運行期間動態增加功能的方式,稱之為"裝飾器"(Decorator),裝飾器的功能非常強大,裝飾器一般接受一個函數對象作為參數,以對其進行增強,相當于C++中的構造函數,與析構函數。

裝飾器本質上是一個python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象.它經常用于有迫切需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景.裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼并繼續重用.

  • 裝飾器本身也是一個函數,其作用是,用于裝飾其他函數.
  • 裝飾器是一個閉包函數是嵌套函數,通過外層函數提供嵌套函數的環境
  • 裝飾器在權限控制,增加額外功能,如增加記錄日志,緩存處理,發送郵件用的比較多

6.1 無參裝飾器

原函數中不帶參數的裝飾器,如下例子假設:我定義了一個函數lyshark(),現在想要在不改變原來函數定義的情況下,在函數運行前打印一段話,函數運行后打印另一段話,此時我們可以使用裝飾器的裝飾功能來簡單的實現這個需求.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner():print("主函數開始執行前,會先執行我!")result=function()print("主函數執行結束后,要在執行我!")return resultreturn inner# (1) @ + 函數名,直接作用在需要裝飾的函數上一行
# (2) 自動執行outer函數并且將下面的函數名lyshark()當做參數傳遞到outer()
# (3) 將outer函數的返回值inner,重新賦值給lyshark()函數
>>> @outer
def lyshark():print("lyshark 的主函數體,裝飾器在裝飾我(*^_^*)")return "check ok"#==調用并執行函數,結果如下==========================================
>>> ret=lyshark()
主函數開始執行前,會先執行我!
lyshark 的主函數體,裝飾器在裝飾我(*^_^*)
主函數執行結束后,要在執行我!>>> print("lyshark()函數的返回值: ",ret)
lyshark()函數的返回值:  check

上方代碼的執行流程是這樣的,步驟如下:

  • 1.當我們調用lyshark()函數時,會自動檢查lyshark()函數上是否有裝飾器
  • 2.如果有則將lyshark()函數的指針,傳遞給裝飾器outer(function)
  • 3.outer(function)接到指針后,執行嵌套函數內的inner(),則先執行print打印一段話
  • 4.由于lyshark()函數指針,傳遞給了function變量,執行function()則相當于執行lyshark()
  • 5.接著最后一步執行打印一段結束的話,并執行返回,返回inner

6.2 有參裝飾器

原函數帶一個參數的裝飾器: 我們在以上的案例中,給裝飾器添加一個參數,并在內部使用這個參數.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner(args):print("主函數開始執行前,會先執行我!")ret=function(args)print("主函數執行結束后,要在執行我!")return retreturn inner>>> @outer
def lyshark(args):print(args)return 0#==調用并執行函數,結果如下==========================================
>>> ret=lyshark("hello world!")
主函數開始執行前,會先執行我!
hello world!
主函數執行結束后,要在執行我!>>> print("lyshark 的返回值是:",ret)
lyshark() 函數的返回值是: 0

原函數帶兩個參數的裝飾器: 接下來繼續演示一下,帶有兩個參數的裝飾器,3個4個,以此類推.

>>> import os
>>> import sys
>>> 
>>> 
>>> def outer(function):def inner(x,y):print("主函數開始執行前,會先執行我!")ret=function(x,y)print("主函數執行結束后,要在執行我!")return retreturn inner>>> @outer
def lyshark(x,y):print(x,y)return 0#==調用并執行函數,結果如下==========================================
>>> ret=lyshark("Hello","LyShark")
主函數開始執行前,會先執行我!
Hello LyShark
主函數執行結束后,要在執行我!>>> print("lyshark() 函數的返回值是:",ret)
lyshark() 函數的返回值是: 0

傳遞一個萬能參數: 裝飾器也可傳遞一個萬能參數,通過此參數傳遞列表字典等.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner(*args,**kwargs):print("主函數開始執行前,會先執行我!")ret=function(*args,**kwargs)print("主函數執行結束后,要在執行我!")return retreturn inner>>> @outer
def lyshark(*args):print(args)return 0#==調用并執行函數,結果如下==========================================
>>> num=[1,2,3,4,5]
>>> ret=lyshark(num)
主函數開始執行前,會先執行我!
([1, 2, 3, 4, 5],)
主函數執行結束后,要在執行我!
>>> 
>>> print("lyshark() 函數的返回值是:",ret)
lyshark() 函數的返回值是: 0#==調用并執行函數,結果如下==========================================
@outer
def lyshark_kw(*args,**kwargs):print(args,kwargs)return 0num=[1,2,3,4,5]
kw={"1001":"admin","1002":"guest"}
ret=lyshark_kw(num,kw)

一次使用兩個裝飾器裝飾函數: 如果一個裝飾器不夠用的話,我們可以使用兩個裝飾器,首先將函數與內層裝飾器結合然后在與外層裝飾器相結合,要理解使用@語法的時候到底執行了什么,是理解裝飾器的關鍵.

>>> import os
>>> import sys
>>> 
>>> def outer2(function2):def inner2(*args,**kwargs):print("裝飾器2--->【開始】")ret=function2(*args,**kwargs)print("裝飾器2--->【結束】")return retreturn inner2>>> def outer1(function1):def inner1(*args,**kwargs):print("裝飾器1--->【開始】")ret=function1(*args,**kwargs)print("裝飾器1--->【結束】")return retreturn inner1@outer2
@outer1
def lyshark():print("lyshark 函數被執行了")#==調用并執行函數,結果如下==========================================
>>> lyshark()
裝飾器2--->【開始】
裝飾器1--->【開始】
lyshark 函數執行了
裝飾器1--->【結束】
裝飾器2--->【結束】#==調用并執行函數,結果如下==========================================
@outer1
@outer2
def lyshark_and():print("lyshark_and 函數被執行了")>>> lyshark_and()
裝飾器1--->【開始】
裝飾器2--->【開始】
lyshark_and 函數執行了
裝飾器2--->【結束】
裝飾器1--->【結束】

6.3 帶參裝飾器

前面的裝飾器本身沒有帶參數,如果要寫一個帶參數的裝飾器怎么辦,那么我們就需要寫一個三層的裝飾器,而且前面寫的裝飾器都不太規范,下面來寫一個比較規范帶參數的裝飾器,下面來看一下代碼,大家可以將下面的代碼自我運行一下.

給裝飾器本身添加參數: 接下來我們將給裝飾器本身添加一些參數,使其能夠實現參數傳遞.

>>> import functools
>>> import sys
>>> 
>>> def lyshark(temp=""):                                   #指定裝飾器默認參數def decorator(function):                                #定義裝飾器@functools.wraps(function)                          #使被裝飾的裝飾器的函數名不改變def wrapper(*args,**kwargs):print("主函數開始執行前,會先執行我!")print("{}:{}".format(temp,function.__name__))   #這里調用了裝飾器temp變量ret=function(*args,**kwargs)print("主函數執行結束后,要在執行我!")return retreturn wrapperreturn decorator#==調用并執行函數,結果如下==========================================
>>> #如果不給裝飾器加參數,那么這個裝飾器將使用默認參數 temp="",來填充
>>> @lyshark()
def test(x):print(x+100)>>> test(100)
主函數開始執行前,會先執行我!
:test                         #這里由于沒有傳遞參數則第一項為空,第二項是函數名稱`function.__name__`取出的
主函數執行結束后,要在執行我!#==調用并執行函數,結果如下==========================================
>>> #下面是給裝飾器一個參數,將不是用默認參數 temp="",將變成 temp="LyShark"
>>> @lyshark("LyShark")
def test(x):print(x+100)>>> test(100)
主函數開始執行前,會先執行我!
LyShark:test
主函數執行結束后,要在執行我!

給裝飾器本身添加參數: 接下來我們將給裝飾器本身添加兩個參數,使其能夠傳遞多個參數.

>>> import sys
>>> import os
>>> 
>>> def lyshark(x="Hello",y="LyShark"):def decorator(function):def wrapper():print("主函數執行前,應先執行我!")print(x,y)ret=function()print("主函數執行后,要執行我!")return retreturn wrapperreturn decorator#==調用并執行函數,結果如下==========================================
>>> #使用默認參數的裝飾器:此時 x="Hello" y="LyShark"
>>> @lyshark()
def test():print("我是test(),主函數,裝飾器在裝飾我")>>> test()
主函數執行前,應先執行我!
Hello LyShark
我是test(),主函數,裝飾器在裝飾我
主函數執行后,要執行我!#==調用并執行函數,結果如下==========================================
>>> #給裝飾器指定參數:此時 x="My Name Is :" y="LyShark"
>>> @lyshark("My Name Is :","LyShark")
def test():print("我是test(),主函數,裝飾器在裝飾我")>>> test()
主函數執行前,應先執行我!
My Name Is : LyShark
我是test(),主函數,裝飾器在裝飾我
主函數執行后,要執行我!

本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/63fd2e5b.html
版權聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協議。轉載請注明出處!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36731.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安達發APS|生產計劃排產軟件助力加工制造業智能化轉型

隨著全球經濟一體化的不斷深入,市場競爭日益激烈,加工制造企業面臨著巨大的生存壓力。在這種情況下,企業對于生產計劃的精細化管理需求日益迫切。為了適應這一市場需求,安達發推出了專門針對加工企業的APS生產計劃排產軟件&#x…

新一代構建工具 maven-mvnd

新一代構建工具 maven-mvnd mvnd的前世今生下載安裝 mvndIDEA集成 mvnd的前世今生 maven 作為一代經典的構建工具,流行了很多年,知道現在依然是大部分Java項目的構建工具的首選;但隨著項目復雜度提高,代碼量及依賴庫的增多使得ma…

簡單易懂的 Postman Runner 參數自增教程

目錄 什么是 Postman Runner? Postman Runner 如何實現參數自增? 步驟一:設置全局參數 步驟二:將全局參數帶入請求參數 步驟三:實現參數自增 資料獲取方法 什么是 Postman Runner? Postman Runner 是…

Python爬蟲(1)一次性搞定Selenium(新版)8種find_element元素定位方式

selenium中有8種不錯的元素定位方式,每個方式和應用場景都不一樣,需要根據自己的使用情況來進行修改 8種find_element元素定位方式 1.id定位2.CSS定位3.XPATH定位4.name定位5.class_name定位6.Link_Text定位7.PARTIAL_LINK_TEXT定位8.TAG_NAME定位總結 …

【第一階段】kotlin中反引號中的函數名特點

在kotlin中可以直接中文定義函數,使用反引號進行調用 eg: fun main() {2023年8月9日定義的函數(5) }private fun 2023年8月9日定義的函數(num:Int){println("反引號的用法$num") }執行結果 在Java中is,in可以定義方法,但是在kotlin中is,in是…

資料分析(三)—— 基期、現期、人口、增長量

基期 基期值 現期值 - 增長量 增長量/增長率 現期值/1&#xff08;間隔)增長率 化除為乘 &#xff1a;當增長率&#xff5c;r| < 5% 時&#xff0c;&#xff0c; 注&#xff1a;當選項首位相同&#xff0c;第二位也相同時&#xff0c;只能用直除 基期和差 (結合選…

SolidUI社區-根據Prompt打造人設

背景 隨著文本生成圖像的語言模型興起&#xff0c;SolidUI想幫人們快速構建可視化工具&#xff0c;可視化內容包括2D,3D,3D場景&#xff0c;從而快速構三維數據演示場景。SolidUI 是一個創新的項目&#xff0c;旨在將自然語言處理&#xff08;NLP&#xff09;與計算機圖形學相…

【openwrt學習筆記】dnsmasq源碼閱讀

目錄 一、DHCP(Dynamic Host Configuration Protocol)1.1 前置知識1.2 參考鏈接1.3 IP地址分配代碼分析rfc2131.cdhcp-common.cdhcp.c 1.4 幾個小問題1.4.1 連續IP模式&#xff08;sequential_ip&#xff09;1.4.2 重新連接使用IP地址1.4.3 續約租期1.4.4 不同的MAC地址分配到相…

VS+Qt+C++旅游景區地圖導航源碼實例

程序示例精選 VSQtC旅游景區地圖導航 如需安裝運行環境或遠程調試&#xff0c;見文章底部個人QQ名片&#xff0c;由專業技術人員遠程協助&#xff01; 前言 這篇博客針對<<VSQtC旅游景區地圖導航>>編寫代碼&#xff0c;代碼整潔&#xff0c;規則&#xff0c;易讀。…

【Vue框架】菜單欄權限的使用與顯示

前言 在 【Vue框架】Vue路由配置 中的getters.js里&#xff0c;可以看到有一個應用程序的狀態&#xff08;變量&#xff09;叫 permission_routes&#xff0c;這個就是管理前端菜單欄的狀態。具體代碼的介紹&#xff0c;都以注釋的形式來說明。 1、modules\permission.js 1…

SpringBoot 將項目打包成 jar 包

SpringBoot 將項目打包成 jar 包 一、項目打包成 jar 包 首先在 pom.xml 文件中導入 Springboot 的 maven 依賴 <!-- 將應用打包成一個可以執行的 jar 包 --> <build><plugins><plugin><groupId>org.springframework.boot</groupId><…

學習筆記整理-面向對象-02-認識函數的上下文

一、認識函數的上下文 什么是上下文 垃圾分類&#xff0c;這是非常好的習慣&#xff0c;值得表揚隨手關燈&#xff0c;這是非常好的習慣&#xff0c;值得表揚遛狗栓繩&#xff0c;這是非常好的習慣&#xff0c;值得表揚課后復習&#xff0c;這是非常好的習慣&#xff0c;值得…

【數據結構】單鏈表OJ題(二)

&#x1f525;博客主頁&#xff1a;小王又困了 &#x1f4da;系列專欄&#xff1a;數據結構 &#x1f31f;人之為學&#xff0c;不日近則日退 ??感謝大家點贊&#x1f44d;收藏?評論?? 目錄 一、鏈表分割 &#x1f4a1;方法一&#xff1a; 二、鏈表的回文 &#x…

hosts文件中被添加 windows10.microdone.cn

在網上搜了一圈逗說是之前下過征信中心的安全控件,是微通新成網絡科技有限公司這家公司提供的,也是http://microdone.cn的運營商。后邊只要使用代理,就會跳出來,所以常規處理操作就是去把瀏覽器上的安全控件卸載了。 參考 解決 windows10 的 代理頻繁被自動篡改為windows10.mi…

利用python實現激光雷達LAS數據濾波的7種方式,使用laspy讀寫

激光雷達&#xff08;LiDAR&#xff09;數據在實際應用中可能受到噪聲和不完美的測量影響&#xff0c;因此數據去噪和濾波方法變得至關重要&#xff0c;以提高數據質量和準確性。以下是一些常用的激光雷達數據去噪與濾波方法。 原始數據如下&#xff1a; 1. 移動平均濾波&…

kubernetes中PV和PVC

目錄 一、PV、PVC簡介 二、PV、PVC關系 三、創建靜態PV 1.配置nfs存儲 2.定義PV 3.定義PVC 4.測試訪問 四、 搭建 StorageClass nfs-client-provisioner &#xff0c;實現 NFS 的動態 PV 創建 1. 配置nfs服務 2.創建 Service Account 3.使用 Deployment 來創建 NFS P…

Figma中文社區來啦,云端協作設計你準備好了嗎?

Figma是改變產品設計協作方式的重要工具,但由于沒有中文社區,對國內設計師的約束較大。而擁有全中文UI 界面、功能齊全的即時設計資源廣場,恰好彌補了Figma的這一短板,它也將取代Figma成為設計師新寵。 1、UI組件集 Figma中文社區替代即時設計資源廣場,擁有海量豐富的UI設計組…

【BEV Review】論文 Delving into the Devils of Bird’s-eye-view 2022-9 筆記

背景 一般來說&#xff0c;自動駕駛車輛的視覺傳感器&#xff08;比如攝像頭&#xff09;安裝在車身上方或者車內后視鏡上。無論哪個位置&#xff0c;攝像頭所得到的都是真實世界在透視視圖&#xff08;Perspective View&#xff09;下的投影&#xff08;世界坐標系到圖像坐標系…

ssm柚子云電子商城java圖書購物電子商務管理jsp源代碼

本項目為前幾天收費幫學妹做的一個項目&#xff0c;Java EE JSP項目&#xff0c;在工作環境中基本使用不到&#xff0c;但是很多學校把這個當作編程入門的項目來做&#xff0c;故分享出本項目供初學者參考。 一、項目描述 ssm柚子云電子商城 系統有2權限&#xff1a;前臺、后…

SpringBoot筆記:SpringBoot 集成 Dataway 多數據源配置(二)

文章目錄 前言核心代碼和配置yml 配置注入多數據源常用Spi實現swagger 配置自定義 Udf指定數據源進行查詢 前言 之前簡單介紹了一下 Dataway 使用&#xff0c;本文繼續介紹一下它的多數據源配置和使用。 核心代碼和配置 yml 配置 # springboot多環境配置 #端口&#xff0c;…