python中的類裝飾器應用場景_這是我見過最全面的Python裝飾器教程了!

裝飾器(Decorators)是 Python 的一個重要部分。簡單地說:他們是修改其他函數的功能的函數。他們有助于讓我們的代碼更簡短,也更Pythonic(Python范兒)。在程序開發中經常使用到的功能,合理使用裝飾器,能讓我們的程序如虎添翼。

1. 函數名應用

函數名是什么?函數名是函數的名字,本質:變量,特殊的變量。

1 ) 函數名就是函數的內存地址,直接打印函數名,就是打印內存地址

def func1():

print(123)

print(func1)         #

2 ) 函數名可以作為變量

def func1():

print(111)

f = func1

f()           # f() 就是func1()

3 ) 函數名可以作為函數的參數

def func1():

print(111)

def func2(x):

x()

func2(func1)         #func1作為func2的參數

4 ) 函數名可以作為函數的返回值

def wrapper():

def inner():

print('inner')

return inner

f = wrapper()

f()

5 ) 函數名可以作為容器類類型的元素

使用for循環批量執行函數

def func1():

print('func1')

def func2():

print('func2')

def func3():

print('func3')

l1 = [func1,func2,func3]

for i in l1:

i()

像上面函數名這種,叫做第一類對象。

第一類對象( first-class object)指:

1.可在運行期創建

2.可用作函數參數或返回值

3.可存入變量的實體

*不明白?那就記住一句話,就當普通變量用

2. 閉包

1、 閉包函數 : 內部函數包含對外部作用域而非全局作用域變量的引用,該內部函數稱為閉包函數

2、閉包的作用:爬蟲、裝飾器

當程序執行遇到函數執行時,會在內存空間開辟局部命名空間,當函數執行完畢,該命名空間會被銷毀。但是如果這個函數內部形成閉包,則該內存空間不會隨著函數執行完而消失。

3、如何判斷是否是閉包:print(函數名.__closure__) 結果是 cell 說明是閉包,結果是 None 說明不是閉包。

閉包舉例

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

wrapper() # summer

如何判斷它是否是一個閉包函數呢? 內層函數名.__closure__ cell 就是=閉包

例 1.

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

執行輸出:

summer

(,)

例 2.

name = 'summer'

def wrapper():

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

結果輸出:

summer

None

返回值為None 表示它不是閉包,因為name是一個全局變量,如果函數調用了外層變量而非全局變量,那么它就是閉包。

例 3.

name = 'summer'

def wrapper2():

name1 = 'spring'

def inner():

print(name)

print(name1)

inner()

print(inner.__closure__)

wrapper2()

結果輸出:

summer

spring

(,)

只要引用了外層變量至少一次,非全局的,它就是閉包

例 4:判斷 下面的函數,是一個閉包嗎? ******

name = 'summer'

def wraaper2(n):        #相當于n = 'summer'

def inner():

print(n)

inner()

print(inner.__closure__)

wraaper2(name)

結果輸出:

summer

(,)

它也是一個閉包. 雖然wraaper2傳了一個全局變量,但是在函數wraaper2內部,inner引用了外層變量,相當于在函數inner外層定義了 n = 'summer',所以inner是一個閉包函數

閉包的好處 : 當函數開始執行時,如果遇到了閉包,他有一個機制,他會永遠開辟一個內存空間,將閉包中的變量等值放入其中,不會隨著函數的執行完畢而消失。

舉一個例子:爬3次,內存開了3次,很占用內存

from urllib.request import urlopen

content1 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content2 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content3 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

把它封裝成閉包

from urllib.request import urlopen

def index():

url = "https://www.cnblogs.com/"

def get():

return urlopen(url).read()

return get        #return的是get,就是一個函數名

cnblog = index()

print(cnblog) # .get at 0x02F46978>

content = cnblog()

print(content) # 頁面源碼

這個例子,只有第一遍,是從網站抓取的。之后的執行,直接從內存中加載,節省內存空間

3.裝飾器

3.1 裝飾器初識

裝飾器本質: 就是一個python函數,他可以讓其他函數在不需要做任何代碼變動的前提下,增加額外的功能,裝飾器的返回值也是一個函數對象。

裝飾器的應用場景:比如插入日志,性能測試,事務處理,緩存等等場景。

import time

def timmer(f):

def inner():

start_time = time.time()

f()

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner

def func1():

print('in func1')

time.sleep(1)

func1 = timmer(func1)

print(func1)

func1()           # 這里的func1是全新的func1,就是上面的賦值,此時相當于執行 inner函數

輸出結果:

.inner at 0x03822DF8>

in func1

此函數的執行時間為1.0003533363342285

代碼從上至下執行

語法糖: 想測試誰,前面加@裝飾器函數,即可。 寫裝飾器,約定俗成,函數名為wrapper

def wrapper(func):

def inner(*args,**kwargs):

'''被裝飾函數之前'''

ret = func(*args,**kwargs)

'''被裝飾函數之后'''

return ret

return inner

@wrapper

def func(*args,**kwargs):

print(args,kwargs)

return 666

print(func())

輸出結果:

() {}

666

裝飾器利用return制造了一個假象,func()執行,其實是執行inner() , func()把原來的func()給覆蓋了

3.2 裝飾器傳參

例 1: 上面裝飾器的例子,func1,要傳2個參數a,b

import time

def timmer(f):

def inner(a,b):

start_time = time.time()

f(a,b)

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner

@timmer

def func1(a,b):

print('in func1 {}{}'.format(a,b))

time.sleep(1) # 模擬程序邏輯

func1(1,2)

執行輸出:

in func1 12

此函數的執行時間為1.0006024837493896

例 2: 如果有多個參數呢?改成動態參數

import time

def timmer(f):

def inner(*args,**kwargs):

start_time = time.time()

f(*args,**kwargs)

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner

@timmer

def func1(*args,**kwargs):

print('in func1 {}{}'.format(args,kwargs))

time.sleep(1) # 模擬程序邏輯

func1(1,2,a='3',b=4)

執行輸出:

in func1 (1, 2){'b': 4, 'a': '3'}

此函數的執行時間為1.000101089477539

函數的執行時,*打散 ;

函數的定義時,*聚合。

from functools import wraps

def wrapper(f): # f = func1

def inner(*args,**kwargs):       #聚合,args (1,2,3)

'''執行函數之前的相關操作'''

ret = f(*args,**kwargs)      # 打散 1,2,3

'''執行函數之后的相關操作'''

return ret

return inner

@wrapper # func1 = wrapper(func1) func1 = inner

def func1(*args):       #args (1,2,3) 聚合

print(666)

return args

print(func1(*[1,2,3]))

執行輸出:

666

(1, 2, 3)

例 3 *****

import time #1.加載模塊

def timmer(*args,**kwargs): #2.加載變量 5.接收參數True,2,3

def wrapper(f): #6.加載變量 8.f = func1

print(args, kwargs) #9.接收timmer函數的值True,2,3

def inner(*args,**kwargs): #10.加載變量. 13.執行函數inner

if flag: #14 flag = True

start_time = time.time() #15 獲取當前時間

ret = f(*args,**kwargs) #16 執行func1

time.sleep(0.3) #19 等待0.3秒

end_time = time.time() #20 獲取當前時間

print('此函數的執行效率%f' % (end_time-start_time)) #21 打印差值

else:

ret = f(*args, **kwargs)

return ret #22 返回給函數調用者func1()

return inner #11 返回給函數調用者wrapper

return wrapper #7.返回給函數調用timmer(flag,2,3)

flag = True #3 加載變量

@timmer(flag,2,3) # 4.執行函數timmer(flag,2,3) 17.執行函數func1 兩步:1,timmer(flag,2,3) 相當于執行wrapper 2.@wrapper 裝飾器 func1 = wrapper(func1)

def func1(*args,**kwargs):

return 666 #18 返回給函數調用者f(*args,**kwargs)

print(func1()) #12 執行函數

寫裝飾器,一般嵌套3層就可以了

3.3 多個裝飾器,裝飾一個函數

def wrapper1(func): # func == f函數名

def inner1():

print('wrapper1 ,before func') # 2

func()

print('wrapper1 ,after func') # 4

return inner1

def wrapper2(func): # func == inner1

def inner2():

print('wrapper2 ,before func') # 1

func()

print('wrapper2 ,after func') # 5

return inner2

@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2

@wrapper1 # f = wrapper1(f) 里面的f==函數名f 外面的f == inner1

def f(): # 3

print('in f')

f() # inner2()

執行輸出:

wrapper2 ,before func

wrapper1 ,before func

in f

wrapper1 ,after func

wrapper2 ,after func

哪個離函數近,哪個先計算 。 最底下的先執行

執行順序如下圖:

多個裝飾器,都是按照上圖的順序來的

4. 裝飾器的 __name__ 和 __doc___

__name__:函數名

__doc___:函數的解釋

普通函數

def func1():

"""

此函數是完成登陸的功能,參數分別是...作用。

return: 返回值是登陸成功與否(True,False)

"""

print(666)

func1()

print(func1.__name__) #獲取函數名

print(func1.__doc__) #獲取函數名注釋說明

執行輸出:

666

func1

此函數是完成登陸的功能,參數分別是...作用。

return: 返回值是登陸成功與否(True,False)

這個有什么用呢?比如日志功能,需要打印出誰在什么時間,調用了什么函數,函數是干啥的,花費了多次時間,這個時候,就需要獲取函數的有用信息了

帶裝飾器的函數

def wrapper(f): # f = func1

def inner(*args,**kwargs): #聚合, args (1,2,3)

'''執行函數之前的相關操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''執行函數之后的相關操作'''

return ret

return inner

@wrapper

def func1():

"""

此函數是完成登陸的功能,參數分別是...作用。

return: 返回值是登陸成功與否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

執行輸出:

666

inner

執行函數之前的相關操作

函數裝飾之后,相當于執行了inner函數,所以輸出inner

為了解決這個問題,需要 調用一個模塊wraps

wraps將 被修飾的函數(wrapped) 的一些屬性值賦值給修飾器函數(wrapper) ,最終讓屬性的顯示更符合我們的直覺

from functools import wraps

def wrapper(f): # f = func1

@wraps(f) #f是被裝飾的函數

def inner(*args,**kwargs): #聚合args (1,2,3)

'''執行函數之前的相關操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''執行函數之后的相關操作'''

return ret

return inner

@wrapper

def func1():

"""

此函數是完成登陸的功能,參數分別是...作用。

return: 返回值是登陸成功與否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

執行輸出:

666

func1

此函數是完成登陸的功能,參數分別是...作用。

return: 返回值是登陸成功與否(True,False)

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

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

相關文章

對于個人(注冊表)與團隊(團隊表)(兩張表沒有關聯)的展示與可空判斷

對于個人&#xff08;注冊表&#xff09;與團隊(團隊表)&#xff08;兩張表沒有關聯&#xff09;的展示與可空判斷 1&#xff0c;在Model中只有GroupId沒有名稱&#xff08;GroupName&#xff09;,所以自己定義一個&#xff1a; /// <summary>/// RegistratorMessage 界面…

macos sierra 引導鏡像_真想不到,在win10上可以制作蘋果macOS啟動U盤

不管你使用的是macOS還是Windows10&#xff0c;電腦出現啟動問題是很正常的&#xff0c;原因有很多種&#xff0c;包括(但不限于)文件損壞、硬件故障和錯誤更新等。如果意外發生在蘋果電腦上&#xff0c;可以使用帶有安裝文件的macOS啟動U盤來修復它。這正是在電腦正常工作時應…

搜索引擎使用技巧

一.基本使用 雙引號 代表完全匹配搜索&#xff0c;也就是說搜索結果返回的頁面包含雙引號中出現的所有的詞&#xff0c;連順序也必須完全匹配。bd和Google 都支持這個指令。 例如&#xff1a; “javar高性能程序開發” 減號 代表搜索不包含減號后面的詞的頁面。使用這個指令時減…

python(1) - 數據類型和變量

數據類型&#xff1a; 整數&#xff1a;就是整數&#xff0c;包括正整數&#xff0c;0&#xff0c;負整數 浮點數&#xff1a; 通俗點說&#xff0c;就是小數 長整數&#xff1a; 就是比較長的整型&#xff0c;通常后面會跟一個L 字符串&#xff1a; 字符串需要用“”或’’括起…

powershell awk_談談 PowerShell

萬事萬物&#xff0c;有始有終。直從萌芽拔&#xff0c;高自毫末始。所謂的 Shell&#xff0c;無非是應用程序與操作系統內核進行交互的一個中間程序而已。我本人玩電腦也有很久一陣子了&#xff0c;最開始接觸到的就是Windows 7 操作系統&#xff0c;當時 Windows 7 上市不久&…

設計模式之: 裝飾器模式

什么是裝飾器模式 作為一種結構型模式, 裝飾器(Decorator)模式就是對一個已有結構增加"裝飾".適配器模式, 是為現在有結構增加的是一個適配器類,.將一個類的接口&#xff0c;轉換成客戶期望的另外一個接口.適配器讓原本接口不兼容的類可以很好的合作.裝飾器模式是將一…

python七段數碼管的詳解,Python入門基礎:七段數碼管繪制

1.在學習Python的過程中&#xff0c;運用所學的一些基礎知識&#xff0c;進行一些簡單的編程&#xff0c;可以收獲很多樂趣。在生活中&#xff0c;LED燈無處不在&#xff0c;熒幕顯示的廣告詞&#xff0c;給我們呈現出動態的視覺效果。下面&#xff0c;則以最簡單的顯示日期為例…

@class

使用格式class 類名; class寫在.h文件里&#xff0c;import寫在.m文件里。這樣可以提高編譯效率 import會在導入文件發生變化時重新拷貝編譯&#xff0c;而class只會告訴使用者有這個類&#xff0c;并不會去拷貝。 場景1 使用import&#xff1a;a拷貝b&#xff0c;b拷貝c&#…

python圖標的演變_Python3 生成icon圖標

首先安裝所使用的庫 pillow&#xff0c; pillow 是用來取代 PIL 的&#xff0c; pip3 install pillow 安裝成功圖&#xff1a;A866FFD7-2283-4BFB-8313-DBDEE909A579.png 簡單的代碼&#xff1a; from __future__ import print_function import os, sys from PIL import Image …

IDEA 熱部署 僅支持jdk1.6,1.7

第一安裝 dcevm 下載地址http://ssw.jku.at/dcevm/binaries/ java -jar dcevm-0.2-win.jar &#xff0c;選擇需要安裝該補丁的jdk&#xff0c;點擊按鈕Install即可 第二&#xff1a;IDEA 在Debug模式下運行&#xff0c;這時隨便修改文件&#xff0c;自動發布到tomcat中 超級快…

php中perl配置,Windows下 Apache、PHP和Perl的安裝配置

在安裝AWStats7.0和 JAWStats之前需要配置其環境&#xff0c;而運行AWStats需要perl支持&#xff0c;運行JAWStats需要PHP支持&#xff0c;這篇文章將具體介紹其環境的安裝配置。環境Windows 2003Apache2.2Per5.12lPHP5(開源)Apache&#xff1a;http://httpd.apache.org/Perl&a…

Android常用的一些make命令(轉載)--不錯

原文網址&#xff1a;http://blog.sina.com.cn/s/blog_abc7e49a01011y0n.html 1.make -jXX XX表示數字&#xff0c;這個命令將編譯Android系統并生成鏡像&#xff0c;XX表示可以使用到的CPU核數&#xff0c;這在配置好的電腦上特別有用&#xff0c;公司的16核ubuntu服務器執行…

arraylist 初始化_ArrayList(JDK1.8)源碼解析

既然是看源碼&#xff0c;那我們要怎么看一個類的源碼呢&#xff1f;這里我推薦的方法是&#xff1a;1)看繼承結構看這個類的層次結構&#xff0c;處于一個什么位置&#xff0c;可以在自己心里有個大概的了解。2)看構造方法在構造方法中&#xff0c;看做了哪些事情&#xff0c;…

技術管理:技術負責人所需的四個核心能力

簡述 「技術負責人」這一稱呼其實比較泛了。往大了講&#xff0c;可以指 CTO、技術VP、技術總監&#xff0c;往小了講&#xff0c;可以指 小組Leader、技術主管、架構師 等。 這些不同崗位的「技術負責人」在工作中會處理著各不相同的問題&#xff0c;因此對他能力要求的側重點…

think php f方法,修改ThinkPHP3.2的F方法

修改ThinkPHP3.2的F方法ThinkPHP3.2的F采用的是序列化方式保存數據&#xff0c;由于F方法保存的文件名是已知的可能造成一些數據泄露&#xff0c;所以在此修改F方法直接替換TP的F方法即可function F($name, $value, $pathDATA_PATH) {static $_cache array();$filename $path…

php Pthread 多線程 (二) Worker和Threaded

<?php //Worker是具有持久化上下文(執行環境)的線程對象 //Worker對象start()后&#xff0c;會執行run()方法&#xff0c;run()方法執行完畢&#xff0c;線程也不會消亡 class MySqlWorker extends Worker {private $name ;private $db null;public function __construct…

ios yymodel 將字典轉數組模型_TensorNet——基于TensorFlow的大規模稀疏特征模型分布式訓練框架

TensorNet是什么&#xff1f;TensorNet是一個構建在TensorFlow之上針對廣告推薦等大規模稀疏場景優化的分布式訓練框架。TensorNet的目標是讓所有使用TensorFlow的開發者可以快速的、方便的訓練出稀疏參數超過百億的超大模型。訓練帶有大規模稀疏特征模型的主要挑戰在廣告、搜索…

mysql 索引及索引創建原則

是什么 索引用于快速的查詢某些特殊列的某些行。如果沒有索引&#xff0c; MySQL 必須從第一行開始&#xff0c;然后通過搜索整個表來查詢有關的行。表越大&#xff0c;查詢的成本越大。如果表有了索引的話&#xff0c;那么 MySQL 可以很快的確定數據的位置&#xff0c;而不用查…

php文件怎么制定編碼格式,php文件編碼格式對結果有影響

最近弄個小網站&#xff0c;發現windows下的文件上傳到linux服務器上后&#xff0c;出現了標簽錯亂的問題。比如&#xff0c;我的代碼是&#xff1a;print testtest;但是&#xff0c;瀏覽器的解析格式缺成了下面的樣子:testtest進過不停地搜索&#xff0c;發現了問題所在&#…

【鏈表】Add Two Numbers

題目&#xff1a; You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. Input: (2 -> 4 -> 3) (5…