1. 程式人生 > >簡單地理解 Python 的裝飾器

簡單地理解 Python 的裝飾器

Python有大量強大又貼心的特性,如果要列個最受歡迎排行榜,那麼裝飾器絕對會在其中。

剛接觸裝飾器,會覺得程式碼不多卻難以理解。其實裝飾器的語法本身挺簡單的,複雜是因為同時混雜了其它的概念。下面我們一起拋去無關概念,簡單地理解下Python的裝飾器。

裝飾器的原理

在直譯器下跑個裝飾器的例子,直觀地感受一下。

1234567 # make_bold就是裝飾器,實現方式這裡略去>>>@make_bold...def get_content():...return'hello world'...>>>get_content()'<b>hello world</b>'

make_bold裝飾的get_content,呼叫後返回結果會自動被b標籤包住。怎麼做到的呢,簡單4步就能明白了。

1. 函式是物件

我們定義個get_content

函式。這時get_content也是個物件,它能做所有物件的操作。

12 def get_content():return'hello world'

它有id,有type,有值。

123456 >>>id(get_content)140090200473112>>>type(get_content)<class'function'>>>>get_content<functionget_content at0x7f694aa2be18>

跟其他物件一樣可以被賦值給其它變數。

123 >>>func_name=get_content>>>func_name()'hello world'

它可以當引數傳遞,也可以當返回值

12345678 >>>def foo(bar):...print(bar())...returnbar...>>>func=foo(get_content)hello world>>>func()'hello world'

2. 自定義函式物件

我們可以用class來建構函式物件。有成員函式__call__的就是函式物件了,函式物件被呼叫時正是呼叫的__call__

1234567 classFuncObj(object):def __init__(self,name):print('Initialize')self.name=namedef __call__(self):print('Hi',self.name)

我們來呼叫看看。可以看到,函式物件的使用分兩步:構造和呼叫(同學們注意了,這是考點)。

1234 >>>fo=FuncObj('python')Initialize>>>fo()Hi python

3. @是個語法糖

裝飾器的@沒有做什麼特別的事,不用它也可以實現一樣的功能,只不過需要更多的程式碼。

123456789 @make_bolddef get_content():return'hello world'# 上面的程式碼等價於下面的def get_content():return'hello world'get_content=make_bold(get_content)

make_bold是個函式,要求入參是函式物件,返回值是函式物件。@的語法糖其實是省去了上面最後一行程式碼,使可讀性更好。用了裝飾器後,每次呼叫get_content,真正呼叫的是make_bold返回的函式物件。

4. 用類實現裝飾器

入參是函式物件,返回是函式物件,如果第2步裡的類的建構函式改成入參是個函式物件,不就正好符合要求嗎?我們來試試實現make_bold

12345678 classmake_bold(object):def __init__(self,func):print('Initialize')self.func=funcdef __call__(self):print('Call')return'<b>{}</b>'.format(self.func())

大功告成,看看能不能用。

12345678 >>>@make_bold...def get_content():...return'hello world'...Initialize>>>get_content()Call'<b>hello world</b>'

成功實現裝飾器!是不是很簡單?

這裡分析一下之前強調的構造呼叫兩個過程。我們去掉@語法糖好理解一些。

12345678 # 構造,使用裝飾器時建構函式物件,呼叫了__init__>>>get_content=make_bold(get_content)Initialize# 呼叫,實際上直接呼叫的是make_bold構造出來的函式物件>>>get_content()Call'<b>hello world</b>'

到這裡就徹底清楚了,完結撒花,可以關掉網頁了~~~(如果只是想知道裝飾器原理的話)

函式版裝飾器

閱讀原始碼時,經常見到用巢狀函式實現的裝飾器,怎麼理解?同樣僅需4步。

1. def的函式物件初始化

class實現的函式物件很容易看到什麼時候構造的,那def定義的函式物件什麼時候構造的呢?

12345678 # 這裡的全域性變數刪去了無關的內容>>>globals(){}>>>def func():...pass...>>>globals(){'func':<functionfunc at0x10f5baf28>}

不像一些編譯型語言,程式在啟動時函式已經構造那好了。上面的例子可以看到,執行到def會才構造出一個函式物件,並賦值給變數make_bold

這段程式碼和下面的程式碼效果是很像的。

12345 classNoName(object):def __call__(self):passfunc=NoName()

2. 巢狀函式

Python的函式可以巢狀定義。

123456 def outer():print('Before def:',locals())def inner():passprint('After def:',locals())returninner

inner是在outer內定義的,所以算outer的區域性變數。執行到def inner時函式物件才建立,因此每次呼叫outer都會建立一個新的inner。下面可以看出,每次返回的inner是不同的。

12345678 >>>outer()Before def:{}After def:{'inner':<functionouter.<locals>.inner at0x7f0b18fa0048>}<functionouter.<locals>.inner at0x7f0b18fa0048>>>>outer()Before def:{}After def:{'inner':<functionouter.<locals>.inner at0x7f0b18fa00d0>}<functionouter.<locals>.inner at0x7f0b18fa00d0>

3. 閉包

巢狀函式有什麼特別之處?因為有閉包。

12345 def outer():msg='hello world'def inner():print(msg)returninner

下面的試驗表明,inner可以訪問到outer的區域性變數msg

123 >>>func=outer()>>>func()hello world

閉包有2個特點

  1. inner能訪問outer及其祖先函式的名稱空間內的變數(區域性變數,函式引數)。
  2. 呼叫outer已經返回了,但是它的名稱空間被返回的inner物件引用,所以還不會被回收。

這部分想深入可以去了解Python的LEGB規則。

4. 用函式實現裝飾器

裝飾器要求入參是函式物件,返回值是函式物件,巢狀函式完全能勝任。

123456 def make_bold(func):print('Initialize')def wrapper():print('Call')return'<b>{}</b>'.format(func())returnwrapper

用法跟類實現的裝飾器一樣。可以去掉@語法糖分析下構造呼叫的時機。

12345678 >>>@make_bold...def get_content():...return'hello world'...Initialize>>>get_content()Call

相關推薦

簡單理解 Python裝飾

Python有大量強大又貼心的特性,如果要列個最受歡迎排行榜,那麼裝飾器絕對會在其中。 剛接觸裝飾器,會覺得程式碼不多卻難以理解。其實裝飾器的語法本身挺簡單的,複雜是因為同時混雜了其它的概念。下面我們一起拋去無關概念,簡單地理解下Python的裝飾器。 裝飾器的原理 在直譯器下

如何理解python裝飾:讀《簡單 12 步理解 Python 裝飾》筆記

原文:簡單 12 步理解 Python 裝飾器 筆記: 要想理解python裝飾器,需理解以下幾點(本人愚笨,需時刻提醒自己): 1、面向物件!時刻牢記python是面向物件的,python中,一切都是“物件(object)” 2、理解函式的定義和呼叫的區別,理解“賦值不等於呼叫

python3----如何簡單理解Python中的if __name__ == '__main__'

tails 命令 out ons 其中 應該 python -name 1-n 1. 摘要 通俗的理解__name__ == ‘__main__‘:假如你叫小明.py,在朋友眼中,你是小明(__name__ == ‘小明‘);在你自己眼中,你是你自己(__name__ ==

如何理解python裝飾

() 如何 lee 簡單的 存在 port print pytho -s 如何理解裝飾器python 學習遇到的第一個難點是裝飾器。裝飾器的作用是不大規模改動代碼的情況下,增加功能。作用:為已經存在的對象添加額外的功能特點:不需要對對象做任何的代碼上的變動。以一個例子來講裝

理解 Python 裝飾看這一篇就夠了

講 Python 裝飾器前,我想先舉個例子,雖有點汙,但跟裝飾器這個話題很貼切。 每個人都有的內褲主要功能是用來遮羞,但是到了冬天它沒法為我們防風禦寒,咋辦?我們想到的一個辦法就是把內褲改造一下,讓它變得更厚更長,這樣一來,它不僅有遮羞功能,還能提供保暖,不過有個問題,這個內褲被我們改造成了

理解Python裝飾

裝飾器本質上是一個函式,該函式用來處理其他函式,它可以讓其他函式在不需要修改程式碼的前提下增加額外的功能,裝飾器的返回值也是一個函式物件。它經常用於有切面需求的場景,比如:插入日誌、效能測試、事務處理、快取、許可權校驗等應用場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大

12步教你理解Python裝飾

或許你已經用過裝飾器,它的使用方式非常簡單但理解起來困難(其實真正理解的也很簡單),想要理解裝飾器,你需要懂點函數語言程式設計的概念,python函式的定義以及函式呼叫的語法規則等,雖然我沒法把裝飾器變得簡單,但是我希望可以通過下面的步驟讓你由淺入深明白裝飾器是什麼。假定你擁有最基本的Pyt

如何簡單理解Python中的if __name__ == '__main__'

1. 摘要 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。 if __name__ == '__mai

如何簡單理解Python中的if __name__ == '__main__' 如何簡單理解Python中的if __name__ == '__main__'

如何簡單地理解Python中的if __name__ == '__main__' 1.摘要 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__na

[轉]理解Python裝飾

作者:xlzd 連結:http://www.zhihu.com/question/26930016/answer/81263287 來源:知乎 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。簡單來講,可以不嚴謹地把Python的裝飾器看做一個包裝函式的函式。比如,有一個函式:def fu

如何理解Python裝飾

Python 裝飾器使用非常地簡單。任何會使用 Python 函式的人都可以學習使用裝飾器: Python 123@somedecoratordefsome_function():print("Check it out, I

Python簡單理解Python中的if __name__ == '__main__'

轉載一篇寫的非常好的部落格 原文地址: 以下為原文 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')

深入理解Python 裝飾(decorator)

返璞歸真, 看山還是山 剛看到Python裝飾器時, 覺得很神奇。簡單實驗下,發現也就那麼回事。但是慢慢的看到越來越多的裝飾器。很多時候又不瞭解到底是怎麼回事了。 最後還是決定好好研究下。 先看看一些例項, 然後再來分析下原理 假設我們有如下

python 裝飾】深入理解python裝飾

要想徹底搞懂Python中的裝飾器,除了需要有一點Python中的函式基礎,還需要解決如下四個問題。當我們解決了這四個問題後,也就徹底搞懂Python中的裝飾器。 1.什麼是裝飾器,其本質是什麼? 2.裝飾器有什麼作用? 3.裝飾器有什麼使用特點(使用原則)?

python裝飾三種裝飾模式的簡單理解

學設計模式中有個裝飾模式,用java實現起來不是很難,但是遠遠沒有python簡單,難怪越來越火了! 這裡就簡單討論下python的幾種裝飾模式: 一 無參裝飾器: # 裝飾器 import time # 裝飾器,記錄函式執行時間 def decorator01(fun): def w

python裝飾簡單理解

1、裝飾器是什麼? 裝飾器,顧名思義,就是用來“裝飾”的。 它長這個樣: @func_name 它能裝飾的東西有:函式、類 2,為何需要裝飾器? 先來打個比方,內褲可以用來遮羞,但是到了冬天它沒法為我們防風禦寒,聰明的人們發明了長褲,有了長褲後寶寶再也不冷了,裝飾器就

python裝飾簡單理解

裝飾器定義:1、把一個函式名當作實參傳給另外一個函式(在不修改裝飾函式原始碼的情況下為其新增功能)         2、返回值中包含函式名(不改變函式呼叫方式) 原始碼: 1 def f(): 2 def f(): 3 time.sleep(2) 4 print('i am

Python裝飾的通俗理解

python 裝飾器 python裝飾器 在學習Python的過程中,我相信有很多人和我一樣,對Python的裝飾器一直覺得很困惑,我也是困惑了好久,並通過思考和查閱才能略有領悟,我希望以下的內容會對你有幫助,我也努力通過通俗的方式使得對Python裝飾器的理解更加的透徹,很多人對裝飾器難以理解,

Python 裝飾簡單示例

裝飾器簡單裝飾器示例: def servlet(func): print("into servlet")#1 print(servlet)#2 def foo(): print("into foo")#7 print(func)#8,真正的bar函數

Python裝飾理解

python裝飾器 高階函數 out 發現 分享 打印 內部 存儲 -i 本文介紹Python其中一個強大的功能--裝飾器 裝飾器本質上就是一個函數,在不修改源代碼,調用方法的前提下,用來給其他函數添加功能的函數 想象一下,你已經開發完成一個功能,並且投入應用中,卻發