本文為《爬著學(xué)Python》系列第四篇文章拂蝎。
從本篇開始弃甥,本專欄在順序更新的基礎(chǔ)上,會有不規(guī)則的更新典予。
在Python的學(xué)習(xí)與運用中甜滨,我們遲早會遇到裝飾器,這個概念對于初識裝飾器的新手來說可能理解起來會有一些障礙瘤袖。但究其原因衣摩,新手之所以覺得裝飾器理解起來有困難,是因為對Python對象、函數(shù)對象的理解不夠深刻艾扮。希望本文能夠幫助有困惑的新手通過鞏固對Python對象的認識來輕松地理解裝飾器既琴。
廢話少說,開始正文吧泡嘴。
裝飾器是什么
Python的裝飾器一般來說是以這樣的形式出現(xiàn)的:
@decorator
def func(*args):
print('func_text')
return 0
我們注意到在定義函數(shù)時甫恩,我們先以@
聲明了一個裝飾名。這個形式作為Python的語法糖酌予,對于熟悉裝飾器的人來說非常便利磺箕,但不利于初學(xué)者理解。好在抛虫,Python語言中的裝飾器還有既易于理解也不繁瑣冗長的形式:
def func(*args):
print('func_text')
return 0
func = decorator(func)
上面這個代碼非常好理解松靡,在我們定義完一個函數(shù)以后,我們通過另一個函數(shù)調(diào)用它建椰,并且把這次調(diào)用的結(jié)果賦值給這個函數(shù)雕欺。
什么情況下我們會需要這么做呢?也就是說棉姐,我們需要decorator
這個函數(shù)做什么事情呢屠列?這個decorator
函數(shù)一般長下面這個樣子:
def decorator(func):
def inner():
print('something before func')
func()
print('something after func')
return inner
從代碼中可以看到,我們在裝飾函數(shù)中定義了一個內(nèi)部函數(shù)伞矩,在這個內(nèi)部函數(shù)中調(diào)用作為參數(shù)傳進來的待修飾函數(shù)笛洛,并且做了一些微小的工作。我們在不影響func
函數(shù)結(jié)構(gòu)的前提下對它的功能進行了修改乃坤,使它在完成自身功能的同時也能適應(yīng)我們給他的變化撞蜂。
在使用裝飾器之前,我們調(diào)用func
輸出結(jié)果是這樣的:
>>> func()
'func_text'
在裝飾器的作用下侥袜,我們再調(diào)用func
輸出:
>>> func = decorator(func)
>>> func()
'something before func'
'func_text'
'something after func'
很顯然望薄,我們沒有改func
函數(shù)內(nèi)部的代碼冀痕,我們沒有改變它本該做到的事情追城,但是我們讓它可以做一些額外的事情您访。這是我們看到現(xiàn)在func = decorator(func)
裝飾方法的邏輯蹋艺。在我們調(diào)試某個函數(shù)驱犹,或者需要記錄時間戳或加入工作日志時鸵贬,這些就可以靠裝飾器做到脚线,并且可以進行批量操作宣蠕。
但是例隆,裝飾器不止這么簡單而已,它能實現(xiàn)的功能要豐富得多抢蚀。但在進一步研究裝飾器的功能之前镀层,我覺得我們有必要加深對Python函數(shù)的認識。那么不妨再回頭看看皿曲,為什么我們可以進行剛才的這些操作唱逢。這里所說的操作吴侦,包括:給函數(shù)賦值,函數(shù)作為值賦給另一個函數(shù)坞古,函數(shù)作為參數(shù)在另一個函數(shù)中調(diào)用备韧。
在以上三個操作中,都是以"函數(shù)"作為主體痪枫,但事實上织堂,這三個"函數(shù)"并不都是同一種東西。在Python中說到"函數(shù)"奶陈,有些時候易阳,我們是指函數(shù)對象,而有些時候尿瞭,我們指的是函數(shù)變量闽烙。這兩個概念到底有什么區(qū)別呢?
Python中的對象
>>> a = 3
在我們對整數(shù)變量賦值時声搁,a
是整型變量黑竞,3
是一個整數(shù)對象。在Python中疏旨,從內(nèi)存中新建對象3
很魂,我們把變量指向這個對象,就完成了變量的賦值檐涝。這也是為什么Python中不需要聲明變量類型遏匆,因為它本來就沒有類型,它更類似于名稱或者標(biāo)記谁榜。變量指向什么類型的對象幅聘,我們可以看作(事實上無類型)這個變量就是這個類型的變量,可以依此把他叫做整型變量或者浮點型變量等窃植。
雖然實質(zhì)上變量本身依然只是個標(biāo)記而已帝蒿,但是我們使用這個變量的時候,目的不是使用它的名稱巷怜,目的在于使用它的對象葛超。我們需要變量來省去直接使用對象的不方便的地方。
就好比說延塑,如果沒有人民代表绣张,開不成人民代表大會。但是我們不在乎人大代表是誰关带,我們只在乎他是誰的人大代表侥涵,他代表那些人民有什么樣的訴求 :)
在給a
賦值以后,我們就完成了變量a
的聲明,同時這個變量指向了一個對象3
独令,同時我們得到了一個叫做"a"的對象端朵。從此開始a
既是變量又是對象。那么怎么區(qū)分呢燃箭?目前可先簡單理解為冲呢,當(dāng)a
出現(xiàn)在賦值語句=
左邊時它是變量,在右邊它就是對象招狸。那么為什么Python要這么設(shè)計呢敬拓?因為這是動態(tài)語言所具有的特征。
這樣做的好處在于裙戏,我們對變量的操作更加靈活乘凸。Python的一句賦值語句就涵蓋了大量的操作與信息,這也是Python能比其他語言簡短但運行速度不足的典型(當(dāng)然也有很多情況下運行反而更便捷累榜,以后會深入[1])营勤。
>>> b = a
在這樣的理解作為前提下,像這樣的對另一個變量賦值操作壹罚,邏輯就變成了:b指向a指向的對象葛作。換句話說,b
的3
和a
的3
是同一個3
猖凛。這和"a的值是3赂蠢,b和a的值相等,b的值也等于3"是不一樣的邏輯辨泳∈瘢看起來差不多,或者說理解起來有難度是因為菠红,3
作為一個整數(shù)它是不可變對象第岖,當(dāng)a
指向一個可變對象時就好理解了。這個在下一部分函數(shù)對象中會進一步進行說明试溯,我們會理解的绍傲。
在此我們可以先再舉一個喜聞樂見的具有Python特色的例子(Python與爬蟲的簡單介紹):
>>> a = 3
>>> b = 4
>>> a, b = b, a
我們對于變量換值的理解為"a的值給b,b的值給a"耍共,計算機執(zhí)行時只能一句一句執(zhí)行,所以往往需要中間變量來緩存先被換掉的值猎塞。我們的人腦能完成"a的值給b试读,b的值給a"操作,那是因為我們記得a原來是多少荠耽,b原來是多少钩骇,簡單的操作不至于讓我們?nèi)四X忘記原來的值。但是電腦比較程序化,它只能記住a目前的值是多少倘屹,沒人告訴它就算把別的值給a银亲,也別忘了a原來的值。Python支持多變量同時賦值纽匙,且賦值完成前务蝠,變量對應(yīng)的對象指向的對象不會變,賦值完成后變量的烛缔。在a, b = b, a
這個語句的執(zhí)行邏輯是這樣的:
-要對a
和b
進行操作馏段,如果沒有那就要新建變量叫作a或者b,有那就太好了
-這個操作是賦值践瓷,需要兩個對象
-這兩個對象分別是b
指向的對象4
和a
指向的對象3
-將a
和b
分別指向?qū)ο?code>4和對象3
(以上是為了方便理解Python對象而作的解釋院喜,有關(guān)可迭代對象的賦值操作實現(xiàn)細節(jié)不在本文討論范圍內(nèi))
這樣的邏輯優(yōu)點在于,a
和b
甚至可以是不一樣的數(shù)據(jù)類型(再次強調(diào)Python變量其實沒有數(shù)據(jù)類型)晕翠,可以是字符串和列表進行對換(暫時想不到在什么場景有必要)喷舀。我們甚至可以對等式右邊的對象進行一些簡單的操作,比如a, b = b, a + b
也是可以的淋肾,某些時候a, b = b, a(b)
也是可以的硫麻,某些時候a, b = b, a()
也是可以的……
>>> def a(n=None):
... print(n)
...
>>> b = 'heart'
>>> a, b = b, a()
None
>>> print(b)
None
>>>
所以有時候不要懊惱為什么癡情會什么都換不來,生活要比Python更靈活巫员,但我可以確定是你換的對象不對 :)
在以上的例子中庶香,我們可以看到如何Python用靈巧的變量聲明方式來節(jié)省內(nèi)存(很久以后會出一篇討論Python的內(nèi)存管理機制[2])的同時簡化流程。我們在引用對象時简识,真正引用的是對象指向的內(nèi)存單元赶掖,可以說是對象的對象。我們可以直接理解成我們在把變量當(dāng)作對象引用七扰,但我們要搞清楚背后的原理奢赂。
總結(jié)起來,
- 在Python中變量是內(nèi)存單元的一種標(biāo)識颈走,我們可以把這個變量當(dāng)作概念對象來引用膳灶,實際上我們在操作內(nèi)存單元這個實際對象
- Python的一切皆為對象指的是概念對象。這叫做變量的引用語義立由。
那么現(xiàn)在先留個問題:Python是如何用這樣的對象定義方法處理內(nèi)置的簡單數(shù)據(jù)結(jié)構(gòu)如list轧钓、set、tuple的呢锐膜?它們自己是對象毕箍,但是他們還有元素啊,那些元素怎么處理呢道盏,列表如何最終指向內(nèi)存單元的一個個值呢而柑?
這個問題先存疑文捶,在本文靠后的部分會給出一點我的見解。
以上算是對Python中對象的一種膚淺的解釋媒咳。這是為了我們理解接下來的函數(shù)對象做個鋪墊粹排。
函數(shù)對象
現(xiàn)在回到我們之前的問題,為什么在Python中說到函數(shù)涩澡,有些時候顽耳,我們是指函數(shù)對象,而有些時候筏养,我們指的是函數(shù)變量斧抱?
之所以會有這種現(xiàn)象,是因為函數(shù)對象并不是所有語言中都默認或者說常見的渐溶,比如在C/C++中辉浦,我們需要通過函數(shù)指針或類或結(jié)構(gòu)體來完成類似函數(shù)對象功能(能力各有不同)。C語言的靈魂在于指針茎辐,Python的靈魂在于一切皆為對象宪郊。
如果我們把Python中的函數(shù)也當(dāng)作剛才的a
和b
就好理解了,函數(shù)的定義和變量賦值其實是差不多的操作拖陆,都是在進行變量的初始化弛槐。所以你進行
>>> def a():
... return 3
...
>>> b = 3
這兩個操作可以看作事實上是同一種操作,只不過賦值的對象類型不同依啰,所以我們把他們看作不同的變量或?qū)ο蠛醮N覀儼補稱作函數(shù),把b稱作整數(shù)速警。
所以叹誉,我們可以進行這樣的操作:
>>> c = a
>>> d = a()
這兩行語句執(zhí)行的結(jié)果是,c
指向了return 3
這個函數(shù)闷旧,d
指向了這個函數(shù)的返回值整數(shù)3长豁。我們知道了函數(shù)被調(diào)用的情況下所指向的對象就是它的返回值(如果沒有,就會返回None這個對象忙灼,就是上面我們所舉過的例子)匠襟。
在這基礎(chǔ)之上,我們可以有裝飾器這樣的操作:
def decorator(func):
def inner():
print('something before func')
func()
print('something after func')
return inner
def func(*args):
print('func_text')
return 0
func = decorator(func)
在decorator
函數(shù)的內(nèi)部函數(shù)inner
中我們用到了decorator
的參數(shù)并且調(diào)用它该园,只要這個對象可調(diào)用(callable)酸舍,程序就不會報錯(比如具有__call__方法的類也能適用于這個修飾器)。如果能理解為什么最后賦值是func = decorator(func)
而不是func = decorator(func())
就可以說大致理解了函數(shù)對象這個概念了里初,那么理解裝飾器工作原理也就不難了父腕。
裝飾器怎么用
其實構(gòu)造裝飾器的方法在本文的開頭就已經(jīng)介紹過了。在這里我們就只解釋一下@decorator
方法青瀑。
Python靈活的對象操作給我們構(gòu)造裝飾器帶來了極大的便利璧亮,但是還是有人不滿足,這個方式還是太臃腫斥难。于是Python提供了修飾器語法糖:
def decorator(func):
def inner():
print('something before func')
func()
print('something after func')
return inner
@decorator
def func(*args):
print('func_text')
return 0
可能你會覺得把func = decorator(func)
改成@decorator
也不算什么簡化枝嘶。甚至在我們需要批量修飾一些函數(shù)的時候,前者其實用起來倒比后者還要方便哑诊。
之所以會出現(xiàn)這樣的情況群扶,是因為裝飾器的應(yīng)用場景不局限于此。在給待修飾函數(shù)修補功能時镀裤,這些功能很小時我們叫他修補竞阐,但是這些功能反而要比待修飾函數(shù)本身更重要時,修飾器就充當(dāng)了類似模板的角色暑劝。
試想一下這樣的場景骆莹。在我們使用第三方開發(fā)的框架時,或者我們需要反復(fù)在不同函數(shù)中調(diào)用某個函數(shù)實現(xiàn)功能時担猛,我們可以給這些函數(shù)加一個變量幕垦,然后再把要調(diào)用的函數(shù)當(dāng)作參數(shù)傳進來并且在函數(shù)體內(nèi)調(diào)用。這聽上去就很麻煩傅联,所以我們需要裝飾器簡化這樣的操作先改。
我們一般是先想好了某個函數(shù)需要完成什么功能,要怎樣實現(xiàn)這樣的功能蒸走,然后我們開始定義這個函數(shù)仇奶。因此,當(dāng)我們需要模板來幫助我們創(chuàng)建這個函數(shù)時比驻,我們就可以直接寫出我們需要什么模板
@decorator
def func(*args):
pass
這是符合程序設(shè)計邏輯的该溯。如果我們先定義函數(shù),再利用另一個函數(shù)來調(diào)用這個函數(shù)嫁艇,可能并不如@decorator
方法思路那么流暢朗伶。
因此在程序設(shè)計過程中@decorator
方法往往更實用,它面向設(shè)計步咪,而func = decorator(func)
可能形式上更面向修改论皆。所以前者更適用于開發(fā),后者更適用于運維猾漫。也就是說点晴,程序員對一個順序設(shè)計結(jié)構(gòu)的修飾器有需求,@decorator
方法也就應(yīng)運而生了悯周。
這也是為什么我們見到@decorator
修飾器絕大部分場景是在應(yīng)用第三方庫或者框架進行快速開發(fā)粒督。
到目前為止我們了解了裝飾器的實現(xiàn)原理,裝飾器主要的應(yīng)用場景禽翼,裝飾器大致的應(yīng)用思路屠橄。但是這遠遠達不到實用的程度族跛。在進一步學(xué)習(xí)裝飾器的使用方法前,我們再需要強化一下對函數(shù)的理解锐墙。我們目前對函數(shù)的理解到位了嗎礁哄?試一試就知道了:
def decorator(func):
def inner():
func()
return 1
return inner
def func(*args):
return 2
func = decorator(func)
print(func())
如果能給出以上代碼最終的輸出結(jié)果,那么你對Python函數(shù)這個概念的理解基本上合格了溪北。
正確答案桐绒,輸出:1
。
想不清楚也沒關(guān)系之拨,我們再來像分析a, b = b, a
這個語句的執(zhí)行一樣簡單分析一下這段代碼的執(zhí)行邏輯:
-定義了decorator茉继,指向定義內(nèi)容,返回一個對象inner
-在decorator的內(nèi)部定義函數(shù)inner蚀乔,這個函數(shù)被調(diào)用時會調(diào)用decorator的參數(shù)指向的函數(shù)烁竭,最后返回一個整數(shù)對象1
-定義了func,指向定義內(nèi)容乙墙,返回一個整數(shù)對象2
-對func進行賦值颖变,要找到將decorator(func)所指向的對象
-decorator(func)指向以func為參數(shù)調(diào)用decorator后返回的對象inner
-調(diào)用func函數(shù),指向一個保存了一個函數(shù)對象作為參數(shù)的inner函數(shù)內(nèi)容听想,需要它的返回對象
-在這些函數(shù)內(nèi)容運行過程中腥刹,某個函數(shù)對象返回了整數(shù)對象2,但是沒關(guān)系inner還沒返回對象
-inner返回了整數(shù)對象1
-將整數(shù)對象1作為參數(shù)調(diào)用內(nèi)置print函數(shù)
-輸出1
這里面有個值得深究的地方:如果我們直接調(diào)用inner函數(shù)(沒有外部定義過)汉买,那么會觸發(fā)未定義錯誤衔峰,但是經(jīng)過func = decorator(func)
賦值定義以后,我們知道它指向一個帶參數(shù)的inner蛙粘,這次它就可以直接調(diào)用了垫卤。這是為什么呢?
不知道你還記不記得出牧,本文靠前部分我們曾經(jīng)留了個問題沒解決:Python是如何用對象定義方法處理內(nèi)置的簡單數(shù)據(jù)結(jié)構(gòu)的穴肘?現(xiàn)在我們來處理一下。
我們可以簡單理解為賦值語句有"路由功能"舔痕,但更推薦理解為:在定義列表時评抚,我們真正創(chuàng)建的對象是列表元素,這些元素各自指向一個內(nèi)存單元伯复,然后我們通過創(chuàng)建列表對象來創(chuàng)建一個元素索引的集合慨代,最后我們把變量指向這個列表對象。這種處理方式就像是把列表當(dāng)作一個函數(shù)啸如,把索引當(dāng)作參數(shù)侍匙,返回索引對應(yīng)元素指向的對象。
所以我們要對之前的一個結(jié)論進行修正叮雳。
>>>def a():
... return 3
...
>>>b = 3
我們之前說對函數(shù)定義就類似對變量賦值想暗,其實妇汗,對函數(shù)定義,更像是對列表賦值说莫。
>>>def a():
... return 3
...
>>>b = [3]
這之間的區(qū)別只能靠各位去領(lǐng)會了铛纬。你也可以先往下看再回來體會。
回到剛才的問題唬滑。為什么不能直接調(diào)用inner
,但是賦值以后就可以用新名字直接調(diào)用了棺弊?
我們可以理解為晶密,要使用列表中的元素,我們必須要用列表名[索引]
的方式模她,我們沒辦法在不提及列表名的情況下使用這個元素稻艰。除非,我們用一個變量指向這個元素變量 = 列表名[索引]
侈净,這樣我們就有了一個對象經(jīng)過這個元素的介紹尊勿,找到指向這個元素指向的內(nèi)存單元地址。我們可以通過直接訪問這個變量來訪問該地址畜侦。
經(jīng)過分析后我們可能還可以進一步修正我們的結(jié)論元扔,對函數(shù)定義,其實更像是對元組賦值旋膳。
學(xué)習(xí)Python真有意思:)
裝飾器的基本用法
在上一節(jié)中我們所討論的"裝飾器怎么用"澎语,更傾向于"要裝飾器做什么",現(xiàn)在我么來討論裝飾器的具體操作方法验懊。
為什么說上一節(jié)的"裝飾器怎么用"不純粹呢擅羞。我們已經(jīng)分析過,裝飾器實質(zhì)上是函數(shù)义图,那么减俏,我們實際使用函數(shù)場景中遇到的很多操作還沒有提及。所以碱工,這一節(jié)我們主要講帶參數(shù)的裝飾器娃承,并且在此之前先簡單說一下多層裝飾器調(diào)用順序。
多個裝飾器的調(diào)用很容易看懂痛垛,按照形式上的嵌套理解就可以了草慧。
@redecorator
@decorator
def func(*args):
pass
等價于
func = redecorator(decorator(func))
多層裝飾實際上應(yīng)用不是特別多,理解起來也比較簡單匙头,在此不展開討論了漫谷。接下來我們討論帶參數(shù)的裝飾器。
我們先直接給出需要參數(shù)時蹂析,裝飾器的一般形式:
def foo(a):
def decorator(func):
def inner(*args):
print(a)
return func(*args)
return inner
return decorator
@foo('hello')
def bar(c):
print(c)
return 0
bar('world')
在這個形式中舔示,@foo(a)
相當(dāng)于bar = foo(a)(bar)
碟婆,也就是說,我們要明確一點惕稻,在定義foo
函數(shù)時竖共,foo
需要的參數(shù)是依次滿足的。這么說可能比較抽象俺祠。
@foo
def bar(c):
print(c)
return 0
如果我們在定義foo
裝飾器函數(shù)時聲明了參數(shù)a
公给,那么如果我們使用它裝飾bar
時,不明確a
的對象蜘渣。整個bar
函數(shù)會作為foo
的參數(shù)a
淌铐。正如之前簡單裝飾器那樣,@foo
相當(dāng)于bar = foo(bar)
蔫缸,而如果這樣腿准,顯然和我們的裝飾器功能不適配。
要想讓有參數(shù)的裝飾器函數(shù)能夠裝飾沒有額外參數(shù)的被裝飾函數(shù)拾碌,只要對參數(shù)進行判別就可以了吐葱,無論是isinstance
判別是否是函數(shù)(其實不可以),還是直接判斷有沒有__call__
方法都是可以的校翔。原因在于兩者區(qū)別就在于多了一重嵌套弟跑,拆掉嵌套就可以正常運行了(內(nèi)部用到參數(shù)的地方也要修改)。例如:
def foo(a):
def decorator(func):
def wrap(*args):
if not callable(a):
print(a)
return func(*args)
return wrap
if callable(a):
return decorator(a)
return decorator
@foo
def bar(c):
print(c)
return 0
bar('world')
除了這些需要說明展融,其它倒也沒有太多可說的窖认,因為說白了就是嵌套函數(shù)傳遞參數(shù)。嵌套函數(shù)怎么閉包怎么傳參告希,裝飾器也可以這么做扑浸。因此我們學(xué)習(xí)的重點就不在于裝飾器了,而在于函數(shù)的運用燕偶。關(guān)于函數(shù)的運用喝噪,這個問題又太宏大了一點,我只能說需要靠平時的學(xué)習(xí)一點點去熟悉體會指么。沒有哪個語言會不需要函數(shù)來完成工作酝惧。函數(shù)運用水平和程序設(shè)計能力水平息息相關(guān),任重道遠伯诬。
是的晚唇,我特地開了一節(jié)來說裝飾器的真正使用方法,卻又看似想糊弄過去:)
但是我的本意是盗似,各位要始終記得一點哩陕,裝飾器就是函數(shù)嵌套,加上函數(shù)賦值。我們要理解裝飾器悍及,只需要理解Python函數(shù)對象闽瓢,之后把它當(dāng)函數(shù)用就可以了。學(xué)習(xí)需要靈活和變通心赶,需要保持清醒扣讼。
裝飾器的其他用法
這里裝飾器的其他用法主要指裝飾器在類上的使用。主要包括裝飾類和裝飾類中的方法缨叫。在前面的學(xué)習(xí)過程中椭符,我們提到過
def decorator(func):
def inner():
func()
return 1
return inner
這里面的func
對象不一定是函數(shù),只要它具有__call__方法耻姥,就可以用裝飾器艰山。這也是我們可以用它來裝飾類和類方法的原因。關(guān)于類相關(guān)的知識咏闪,可能要過很久介紹面向?qū)ο缶幊虝r才會提及了。
這里我也不展開講了摔吏,給學(xué)有余力的各位兩個鏈接參考Python——編寫類裝飾器 - Gavin - CSDN博客鸽嫂, Python 裝飾器裝飾類中的方法 - hesi9555的博客 - CSDN博客。
是的征讲,我又糊弄過去了:)
寫在最后
本文是我在進行的系列教程的第一篇長文据某,第一篇真正講解Python技術(shù)的文章。內(nèi)容雖然不多但講得還是比較仔細吧诗箍。前前后后寫了大概四五個小時癣籽。
說到底,本文的目的在于學(xué)習(xí)如何去認識Python裝飾器和函數(shù)滤祖,因此在實用部分我偷懶了(就是這么直接)筷狼。只有認識夠深刻,我們才真正理解如何去用這些東西匠童,為什么這樣去用埂材。但是古話說"紙上得來終覺淺",編程也是這樣汤求,實踐環(huán)節(jié)是容不得偷懶的俏险。而我不愿意講解實戰(zhàn),是因為涉及到函數(shù)運用扬绪、類的設(shè)計這樣的知識的時候竖独,和本文的關(guān)系就不大了,那些都是足夠單獨拿出來研究值得花幾年去訓(xùn)練的東西挤牛,想在一篇文章的一部分里面再怎么講解都會顯得淺薄無力莹痢。弄懂裝飾器工作原理,結(jié)合自身設(shè)計函數(shù)設(shè)計類的能力,自己嘗試去使用裝飾器實現(xiàn)功能格二,這是我無法替你做的劈彪。
再說,畢竟我不是在寫書顶猜、不是在寫論文沧奴,它說到底還是交流性質(zhì)啊长窄!
希望能一起學(xué)習(xí)滔吠,一起進步。
鏈接
- Python 裝飾器為什么難理解挠日? - 知乎專欄
- 如何正確理解Python函數(shù)是第一類對象 - FooFish
- Python——編寫類裝飾器 - Gavin - CSDN博客
- Python 裝飾器裝飾類中的方法 - hesi9555的博客 - CSDN博客
- 最后留個彩蛋吧Stop Writing Classes - YouTube