摘要:今天我們一起探討一下裝飾器的另類用法。語法回顧開始之前我們再將裝飾器的語法回顧一下。例子本身只是演示了裝飾器的一種用法,但不是推薦你就這樣使用裝飾器。類裝飾器在以前,還不支持類裝飾器。
之前有比較系統(tǒng)介紹過Python的裝飾器(請查閱《詳解Python裝飾器》),本文算是一個補(bǔ)充。今天我們一起探討一下裝飾器的另類用法。
語法回顧開始之前我們再將Python裝飾器的語法回顧一下。
@decorate def f(...): pass
等同于:
def f(...): pass f = decorate(f)
@語法的好處在于:
相同的函數(shù)名只出現(xiàn)一次,避免了f = decorate(f)這樣的語句。
可讀性更高,讓讀代碼的人一眼就明白函數(shù)被裝飾了哪些功能。
@call()裝飾器假設(shè)你要創(chuàng)建一個整數(shù)平方的列表,你可以這樣寫:
>>> table = [0, 1, 4, 9, 16] >>> len(table), table[3] (5, 9)
也可以使用列表表達(dá)式,因為我們要實現(xiàn)比較簡單。
>>> table = [i * i for i in range(5)] >>> len(table), table[3] (5, 9)
但是假如這個列表的邏輯比較復(fù)雜的時候,最好是寫成一個方法,這樣會更好維護(hù)。
>>> def table(n): ... value = [] ... for i in range(n): ... value.append(i*i) ... return value >>> table = table(5)
注意看最后一句,是不是很符合裝飾器的語法規(guī)則?什么情況下你會寫這樣的代碼呢?
你需要把相對復(fù)雜業(yè)務(wù)寫成一個方法。
這個方法和返回值可以同名,而且你不希望對外公開此方法,只公開結(jié)果。
你想盡量使用裝飾器。(無厘頭的理由)
那么這時候@call()裝飾器就登場了。
def call(*args, **kwargs): def call_fn(fn): return fn(*args, **kwargs) return call_fn
這個裝飾器會把你傳入的參數(shù)送給目標(biāo)函數(shù)然后直接執(zhí)行。
@call(5) def table(n): value = [] for i in range(n): value.append(i*i) return value print len(table), table[3] # 5 9
@call()裝飾器適用于任何函數(shù),你傳入的參數(shù)會被直接使用然后結(jié)果賦值給同名函數(shù)。這樣避免了你重新定義一個變量來存儲結(jié)果。
@list 裝飾器假如你有一個這樣一個生成器函數(shù)。
def table(n): for i in range(n): yield i
當(dāng)你要生成n=5的序列時,可以直接調(diào)用。
table = table(5) print table #
使用上節(jié)提到的@call()裝飾器,也能得到一樣的結(jié)果。
@call(5) def table(n): for i in range(n): yield i print table #
你還可以直接將其轉(zhuǎn)換成列表。(使用list(generator_object)函數(shù))
@list @call(5) def table(n): for i in range(n): yield i print table # [0, 1, 2, 3, 4]
相信不少同學(xué)第一次看到這個用法應(yīng)該是懵逼的。這等同于列表表達(dá)式,但是可讀性也許差了不少。例子本身只是演示了裝飾器的一種用法,但不是推薦你就這樣使用裝飾器。你這樣用也許會被其他同事拖到墻角里打死。
類裝飾器在Python 2.6以前,還不支持類裝飾器。也就是說,你不能使用這樣的寫法。
@decorator class MyClass(object): pass
你必須這樣寫:
class MyClass(object): pass MyClass = decorator(MyClass)
也就是說,@語法對類是做了特殊處理的,類不一定是一個callable對象(盡管它有構(gòu)造函數(shù)),但是也允許使用裝飾器。那么基于以上語法,你覺得類裝飾器能實現(xiàn)什么功能呢?
舉一個例子,ptest中的@TestClass()用于聲明一個測試類,其源代碼大致如此。
def TestClass(enabled=True, run_mode="singleline"): def tracer(cls): cls.__pd_type__ ="test" cls.__enabled__ = enabled cls.__run_mode__ = run_mode.lower() return cls return tracer
當(dāng)我們在寫一個測試類時,發(fā)生了什么?
@TestClass() class TestCases(object): # your test case ... print TestCases.__dict__ # {"__module__": "__main__", "__enabled__": True, "__pd_type__": "test", "__run_mode__": "singleline", ...}
居然裝飾器的參數(shù)全都變成了變成這個類的屬性,好神奇!我們把語法糖一一展開。
class TestCases(object): pass decorator = TestClass() print decorator #TestCases = decorator(TestCases) print TestCases # print TestCases.__dict__ # {"__module__": "__main__", "__enabled__": True, "__pd_type__": "test", "__run_mode__": "singleline", ...}
當(dāng)裝飾器在被使用時,TestClass()函數(shù)會馬上被執(zhí)行并返回一個裝飾器函數(shù),這個函數(shù)是一個閉包函數(shù),保存了enabled和run_mode兩個變量。另外它還接受一個類作為參數(shù),并使用之前保存的變量為這個類添加屬性,最后返回。所以經(jīng)過@TestClass()裝飾過的類都會帶上__enabled__、__pd_type__以及__run_mode__的屬性。
由此可見,類裝飾器可以完成和Java類似的注解功能,而且要比注解強(qiáng)大的多。
后記裝飾器就是一個語法糖,當(dāng)你看不懂一個裝飾器時,可以考慮將其依次展開,分別帶入。這個語法糖給了我們不少方便,但是也要慎用。畢竟可維護(hù)的代碼才是高質(zhì)量的代碼。
關(guān)于作者:Python技術(shù)愛好者,目前從事測試開發(fā)相關(guān)工作,轉(zhuǎn)載請注明原文出處。
歡迎關(guān)注我的博客 http://betacat.online,你可以到我的公眾號中去當(dāng)吃瓜群眾。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/44238.html
摘要:初步認(rèn)識裝飾器函數(shù)裝飾器用于在源代碼中標(biāo)記函數(shù),以某種方式增強(qiáng)函數(shù)的行為。函數(shù)裝飾器在導(dǎo)入模塊時立即執(zhí)行,而被裝飾的函數(shù)只在明確調(diào)用時運行。只有涉及嵌套函數(shù)時才有閉包問題。如果想保留函數(shù)原本的屬性,可以使用標(biāo)準(zhǔn)庫中的裝飾器。 《流暢的Python》筆記本篇將從最簡單的裝飾器開始,逐漸深入到閉包的概念,然后實現(xiàn)參數(shù)化裝飾器,最后介紹標(biāo)準(zhǔn)庫中常用的裝飾器。 1. 初步認(rèn)識裝飾器 函數(shù)裝飾...
摘要:常規(guī)的使用來統(tǒng)計一段代碼運行時間的例子輸出結(jié)果總結(jié)其實是一門特別人性化的語言,但凡在工程中經(jīng)常遇到的問題,處理起來比較棘手的模式基本都有對應(yīng)的比較優(yōu)雅的解決方案。 python的高級特性 名詞與翻譯對照表 generator 生成器 iterator 迭代器 collection 集合 pack/unpack 打包/解包 decorator 裝飾器 context manager ...
摘要:裝飾器的使用符合了面向?qū)ο缶幊痰拈_放封閉原則。三簡單的裝飾器基于上面的函數(shù)執(zhí)行時間的需求,我們就手寫一個簡單的裝飾器進(jìn)行實現(xiàn)。函數(shù)體就是要實現(xiàn)裝飾器的內(nèi)容。類裝飾器的實現(xiàn)是調(diào)用了類里面的函數(shù)。類裝飾器的寫法比我們裝飾器函數(shù)的寫法更加簡單。 目錄 前言 一、什么是裝飾器 二、為什么要用裝飾器 ...
摘要:作者按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用和兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶崿F(xiàn)方式原文地址是每天一個設(shè)計模式之裝飾者模式歡迎關(guān)注個人技術(shù)博客。 作者按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript和python兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶崿F(xiàn)方式...
摘要:作者按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用和兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶崿F(xiàn)方式原文地址是每天一個設(shè)計模式之裝飾者模式歡迎關(guān)注個人技術(shù)博客。 作者按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript和python兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶崿F(xiàn)方式...
閱讀 635·2023-04-25 18:37
閱讀 2796·2021-10-12 10:12
閱讀 8376·2021-09-22 15:07
閱讀 577·2019-08-30 15:55
閱讀 3184·2019-08-30 15:44
閱讀 2204·2019-08-30 15:44
閱讀 1635·2019-08-30 13:03
閱讀 1570·2019-08-30 12:55