day04-裝飾器

一、裝飾器定義

1)裝飾器:本質是函數。

2)功能:用來裝飾其他函數,顧名思義就是,為其他的函數添加附件功能的。

二、原則

1)不能修改被裝飾函數的源代碼

2)不能修改被裝飾函數的調用方式

如果你寫的這個程序在生產環境下已經運行了,如果修改別人的源代碼或者修改別人的調用方式,那么出了問題,后果可想而知

三、實現裝飾器知識儲備

1)函數即"變量"

2)高階函數

3)嵌套函數

最終: 高階函數+嵌套函數 => 裝飾器

?

3.1 函數即變量

1)python的內存機制

#變量

x?=?1

#函數

def?test():

pass

以上一個變量一個函數在內存中的表現形式如下圖:

?

在python解釋器中,有一個概念叫做引用基數,比方說,x=1,它會先在內存當中把1這個值實實在在的存放下來,這個x其實就是1的門牌號,也是對1的一次引用。python什么時候把這個1這個屋子清空吶?它會等到1所對應的門牌號都沒有了,就會把1這里面的東西給清掉,這個也是python的內存回收機制,就是靠這種方式回收的。

2)del清理

那我們用什么清理吶?用del去清理門牌號,就是對1的值引用的變量,del? x就表示清理掉1對應的x的門派號。如果x沒有被del,則x永遠不還被刪除,除非程序結束了,不然永遠不會被刪除。del刪除的不是1,只是把門牌號x刪除了,只是定期刷新時,發現1沒有被其他門牌號引用了,才會被清掉。

3)函數在內存的表現形式

①bar函數在foo函數之后定義

#bar函數在foo函數之后定義
def foo():print("in the foo")bar()def bar():print("in the bar")foo()

#輸出

in?the foo

in?the bar

bar函數是在foo函數之前定義

# bar函數是在foo函數之前定義
def bar():print("in the bar")def foo():print("in the foo")bar()foo()

#輸出

in?the foo

in?the bar

顯然,兩種寫法效果是一樣的,那我們來看看第三種情況。

③bar函數在foo函數調用之后聲明

# bar函數在foo函數調用之后聲明
def foo():print("in the foo")bar()foo()def bar():print("in the bar")

#輸出

Traceback (most recent call last):

in?the foo

??File?"D:/PycharmProjects/pyhomework/day4/裝飾器/函數即變量.py", line?31,?in?<module>

????foo()

??File?"D:/PycharmProjects/pyhomework/day4/裝飾器/函數即變量.py", line?29,?in?foo

????bar()

NameError: name?'bar'?is?not?defined??#bar函數沒有定義

 

3.2 高階函數

實現高階函數有兩個條件:

1)把一個函數名當做實參傳給另外一個函數

2)返回值中包含函數名

1、把一個函數名當做實參傳給另外一個函數

作用:在不修改被裝飾函數源代碼的情況下為其添加功能

import  time
def bar():time.sleep(3)print("in the bar")def test1(func):print(func)         #相當于print(bar) 函數的內存地址start_time = time.time()func()              #相當于bar() 進入函數內部執行stop_time = time.time()print("the func run the is %s"%(stop_time-start_time))
#沒有修改bar的代碼
test1(bar)  #把bar函數名當做實參傳到test1中

  

#輸出

<function bar at?0x0000000000A7D378>??#bar函數的內存地址

in?the bar?????????????????????????????? #函數值

the func run the?is?2.9912972450256348

2、返回值中包括函數名

作用:不修改函數調用方式

import  timedef bar():time.sleep(3)print("in the bar")def test2(func):print(func)return func   #返回函數的內存地址#調用test2函數
bar = test2(bar)   #重新給bar賦值,打印內存地址(內存地址加上小括號就能打印函數值)
bar()  #bar函數調用方式不變,實現裝飾器的功能

 

相當于@bar

#輸出

<function bar at?0x0000000000B6D378>??#打印bar函數的內存地址

in?the bar

3.3 嵌套函數

1、定義

在一個函數的函數體內,用def 去聲明一個函數,而不是去調用其他函數,稱為嵌套函數。

嵌套函數例子:

def foo():print("in the foo")def bar():  #在foo函數體內,用def聲明一個函數print("in the bar")bar()
#調用foo函數
foo()

 

#輸出

in?the foo

in?the bar

下面這種情況是不是嵌套函數? 

def bar():print("in the bar")def foo():print("in the foo")bar()  #調用bar函數foo()

很顯然不是,因為只是調用了bar函數,沒有用def去聲明一個函數。

  

局部作用域和全局作用域的訪問順序

#局部作用域和全局作用域的訪問順序
x=0
def grandpa():x=1def dad():x=2def son():x=3print(x)son()dad()
#調用grandpa
grandpa()

很顯然最后輸出的是3,這個說明作用域:只能是從里往外找,一層一層的的找。

四、裝飾器實現

4.1 定義

裝飾器實現的條件:高階函數+嵌套函數 =》裝飾器

import time#定義內置函數
def timmer(func):  #timmer(test1) func=test1def deco():start_time = time.time()func()   #run test1()stop_time = time.time()print("the func run time is %s"%(stop_time-start_time))return deco           #返回deco的內存地址#裝飾test1函數
@timmer  
# 相當于test1 = timmer(test1)      test1(),調用deco的內存值。同時也有定義一個test1的變量
def test1():time.sleep(3)print("in the test1")#直接執行test1函數
test1()

#輸出

in?the test1

the func run time?is?3.0002999305725098

執行步驟:

  1. 執行timmer函數,timmer(test1) 返回值賦值給test1變量,即test1=timmer(test1)
  2. 此時的test1的值是執行timmer函數返回值deco,即test1=deco
  3. 所以執行test1,其實就是執行的是deco函數,test1()其實就是執行deco函數。

4.2?執行函數帶參數

import timedef timmer(func):  #timmer(test2) func=test2def deco():start_time = time.time()func()   #run test2()stop_time = time.time()print("the func run time is %s"%(stop_time-start_time))return deco@timmer
def test2(name,age):print("name:%s,age:%s"%(name,age))test2()

  

#輸出

Traceback (most recent call last):

??File?"D:/PycharmProjects/pyhomework/day4/裝飾器/裝飾器高潮.py", line?23,?in?<module>

????test2()

??File?"D:/PycharmProjects/pyhomework/day4/裝飾器/裝飾器高潮.py", line?8,?in?deco

????func()???#run test1()

TypeError: test2() missing?2?required positional arguments:?'name'?and?'age'?#缺少傳入name和age參數

 

很顯然是錯誤的。因為這邊執行的test2函數其實就是執行的deco函數,deco函數體內的func()其實就是執行test2函數,但是,test2需要傳入name和age兩個參數,所以報錯。那怎么解決呢?

傳入確定參數:

import timedef timmer(func):  #timmer(test1) func=test1def deco(name,age):start_time = time.time()func(name,age)   #run test2()stop_time = time.time()print("the func run time is %s"%(stop_time-start_time))return deco@timmer
def test2(name,age):print("name:%s,age:%s"%(name,age))test2('zhou',22)

  

不能確定傳入幾個參數,所以我們用非固定參數傳參。代碼如下:

import timedef timmer(func):  #timmer(test1) func=test1def deco(*args,**kwargs):  #傳入非固定參數start_time = time.time()func(*args,**kwargs)   #傳入非固定參數stop_time = time.time()print("the func run time is %s"%(stop_time-start_time))return deco#不帶參數
@timmer  # 相當于test1 = timmer(test1)
def test1():time.sleep(3)print("in the test1")#帶參數
@timmer
def test2(name,age):print("name:%s,age:%s"%(name,age))
#調用
test1()
test2("Alex",22)

  

#輸出

#test1

in?the test1

the func run time?is?3.0010883808135986

#test2

name:Alex,age:22

the func run time?is?0.0??#test2

?

4.3 執行函數有返回值

def timmer(func):  #timmer(test1) func=test1def deco(*args,**kwargs):res = func(*args,**kwargs) #這邊傳入函數結果賦給resreturn res   # 返回resreturn deco@timmer
def test1():  # test1 =  timmer(test1)print("in the test1")return "from the test1" #執行函數test1有返回值res = test1()
print(res)

  

#輸出

in?the test1

from?the test1

?

?通過上面的例子,可以看出,其實就是在內置函數中把傳入參數的執行結果賦給res,然后再返回res變量。

 

4.4帶參數裝飾器

之前我們的裝飾器都是沒有帶參數的,其實我們已經能解決90%的問題了,但是如果說有一種情況:就是在你訪問不通頁面時,你用的驗證的方式來源不同,這時你該怎么辦?

 

#本地驗證
user,passwd = "zhouqiongjie","abc123"def auth(auth_type):  #傳遞裝飾器的參數print("auth func:",auth_type)def outer_wrapper(func):   # 將被裝飾的函數作為參數傳遞進來def wrapper(*args,**kwargs):  #將被裝飾函數的參數傳遞進來print("wrapper func args:",*args,**kwargs)username = input("Username:").strip()password = input("Password:").strip()if auth_type == "local":if user == username and passwd == password:print("\033[32mUser has passed authentication\033[0m")res = func(*args,**kwargs)print("--after authentication")return reselse:exit("Invalid username or password")elif auth_type == "ldap":passreturn wrapperreturn outer_wrapperdef index():print("welcome to index page")@auth(auth_type="local")  #帶參數裝飾器
def home():print("welcome to home page")return "from home"@auth(auth_type="ldap")   #帶參數裝飾器
def bbs():print("welcome  to bbs page")index()
print(home())
bbs()

  

上面的例子可以看出,執行步驟:

1)??????? outer_wrapper = auth(auth_type="local")

2)??????? home = outer_wrapper(home)

3)home()

所以這個函數的作用分別是:

1)??????? auth(auth_type) 傳遞裝飾器的參數

2)??????? outer_wrapper(func) 把函數當做實參傳遞進來

3)wrapper(*args,**kwargs) 真正執行裝飾的函數

  

轉載于:https://www.cnblogs.com/Study-Blog/p/7400983.html

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

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

相關文章

c 語言bool 類型數據_C ++中的bool數據類型

c 語言bool 類型數據In C programming language, to deal with the Boolean values – C added the feature of the bool data type. A bool variable stores either true (1) or false (0) values. 在C 編程語言中&#xff0c;為了處理布爾值– C 添加了bool數據類型的功能 。…

C ++中的std :: binary_search()

binary_search()作為STL函數 (binary_search() as a STL function) Syntax: 句法&#xff1a; bool binary_search (ForwardIterator first, ForwardIterator last, const T& value);Where, 哪里&#xff0c; ForwardIterator first iterator to start of the range For…

HNUSTOJ-1437 無題

1437: 無題 時間限制: 1 Sec 內存限制: 128 MB提交: 268 解決: 45[提交][狀態][討論版]題目描述 tc在玩一個很無聊的游戲&#xff1a;每一次電腦都會給一個長度不超過10^5的字符串&#xff0c;tc每次都從第一個字符開始&#xff0c;如果找到兩個相鄰相一樣的字符&#xff0c;…

凱撒密碼pythin密碼_凱撒密碼術

凱撒密碼pythin密碼Caesar cipher is one of the well-known techniques used for encrypting the data. Although not widely used due to its simplicity and being more prone to be cracked by any outsider, still this cipher holds much value as it is amongst the fir…

MultiQC使用指導

MultiQC使用指導 官網資料文獻&#xff1a;MultiQC --- summarize analysis results for multiple tools and samples in a single report參考資料一&#xff1a; 整合 fastq 質控結果的工具 簡介 MultiQC 是一個基于Python的模塊, 用于整合其它軟件的報告結果, 目前支持以下軟…

FYFG的完整形式是什么?

FYFG&#xff1a;對您的未來指導 (FYFG: For Your Future Guidance) FYFG is an abbreviation of "For Your Future Guidance". FYFG是“ For your Future Guidance”的縮寫 。 It is an expression, which is commonly used in the Gmail platform. It is also wr…

WorkerMan 入門學習之(二)基礎教程-Connection類的使用

一、TcpConnection類 的使用 1、簡單的TCP測試 Server.php <?php require_once __DIR__./Workerman/Autoloader.php; use Workerman\Worker; $worker new Worker(websocket://0.0.0.0:80);// 連接回調 $worker->onConnect function ($connection){echo "connecti…

kotlin獲取屬性_Kotlin程序獲取系統名稱

kotlin獲取屬性The task is to get the system name. 任務是獲取系統名稱。 package com.includehelpimport java.net.InetAddress/*** Function for System Name*/fun getSystemName(): String? {return try {InetAddress.getLocalHost().hostName} catch (E: Exception) {S…

71文件類型

1.kit類型 標準的SeaJs模塊文件類型&#xff0c;直接對外暴露方法。 2.units類型 依賴pageJob&#xff0c;對外暴露一個名字&#xff0c;pageJob依賴暴露的名字對模塊進行初始化&#xff0c;在pageJob內部邏輯自動執行init方法&#xff1b; 由于沒有對外暴露方法&#xff0c;只…

ruby 生成哈希值_哈希 Ruby中的運算符

ruby 生成哈希值In the last article, we have seen how we can carry out a comparison between two hash objects with the help of "" operator? "" method is a public instance method defined in Ruby’s library. 在上一篇文章中&#xff0c;我們看…

七牛大數據平臺的演進與大數據分析實踐--轉

原文地址&#xff1a;http://www.infoq.com/cn/articles/qiniu-big-data-platform-evolution-and-analysis?utm_sourceinfoq&utm_mediumpopular_widget&utm_campaignpopular_content_list&utm_contenthomepage 七牛大數據平臺的演進與大數據分析實踐 (點擊放大圖像…

最大化切割段

Description: 描述&#xff1a; In this article we are going to review classic dynamic programing problem which has been featured in interview rounds of amazon. 在本文中&#xff0c;我們將回顧在亞馬遜的采訪輪次中已經介紹的經典動態編程問題。 Problem statemen…

響應數據傳出(springMVC)

1. SpringMVC 輸出模型數據概述 提供了以下幾種途徑輸出模型數據&#xff1a; ModelAndView: 處理方法返回值類型為 ModelAndView 時, 方法體即可通過該對象添加模型數據 Map 及 Model: 入參為 org.springframework.ui.Model、 org.springframework.ui.ModelMap 或 java.uti…

python 字母順序計數_計數并說出順序

python 字母順序計數Problem statement: 問題陳述&#xff1a; The count-and-say sequence is the sequence of integers with the first five terms as following: 計數序列是具有前五個項的整數序列&#xff0c;如下所示&#xff1a; 1 1個 11 11 21 21 1211 1211 111221 …

微信網頁掃碼登錄的實現

為了讓用戶登錄網站的門檻更低&#xff0c;微信掃一掃登錄變得越來越廣泛&#xff0c;所以最近加緊趕制的項目中有用到這個功能&#xff0c;此篇文字的出發點基于微信開放平臺已經配置好域名&#xff08;80端口&#xff09;并且認證成功獲得app_id和secret并有權限調用微信的接…

希爾密碼_希爾密碼| 網絡安全

希爾密碼Now, Hill Cipher is a very basic cryptographic technique which is used to convert a string into ciphertext. This technique was invented by an American Mathematician "Lester Sanders Hill". This is a polygraphic substitution cipher because …

Android 那些年,處理getActivity()為null的日子

在日常開發中的時候&#xff0c;我們經常會使用ViewPagerFragment進行視圖滑動&#xff0c;在某些部分邏輯也許我們需要利用上下文Context&#xff08;例如基本的Toast&#xff09;&#xff0c;但是由于Fragment只是衣服在Activity容器的一個試圖&#xff0c;如果需要拿到當前的…

設計模式狀態模式uml_UML的完整形式是什么?

設計模式狀態模式umlUML&#xff1a;統一建模語言 (UML: Unified Modeling Language) UML is an abbreviation of Unified Modeling Language. In the field of software engineering, it is a visual modeling language that is standard in quality. It makes it available t…

idea debug快捷鍵

idea的debug調試快捷鍵 F9 resume programe 恢復程序 AltF10 show execution point 顯示執行斷點 F8 Step Over 相當于eclipse的f6 跳到下一步 F7 Step Into 相當于eclipse的f5就是 進入到代碼 AltshiftF7 Force Step Into 這個…

vqa mcb_MCB的完整形式是什么?

vqa mcbMCB&#xff1a;微型斷路器 (MCB: Miniature Circuit Breaker) MCB is an abbreviation of "Miniature Circuit Breaker". MCB是“微型斷路器”的縮寫 。 It is an automatically operated electronics switch. It is designed to detect the fault in the e…