Python高級(jí)特性之迭代器、生成器、裝飾器和上下文管理器
今天測(cè)試Python高級(jí)特性-迭代器、生成器、裝飾器、上下文管理器。高級(jí)語(yǔ)言特性可以使得程序更加Pythonic,可讀性、可維護(hù)性顯著增加。下面四個(gè)高級(jí)特性,筆者在收集資料以及用ipython測(cè)試。裝飾器的只是測(cè)試基本的功能,筆者覺(jué)得有點(diǎn)復(fù)雜。
1、迭代器
迭代器協(xié)議是指:對(duì)象需要提供next方法,要么返回迭代中的下一項(xiàng),要么就引起一個(gè)StopIteration異常以終止迭代,防止出現(xiàn)無(wú)限循環(huán)的情況。迭代器是一個(gè)可以記住遍歷的位置的對(duì)象。
迭代器有兩個(gè)基本的方法:iter() 和 next()。字符串,列表或元組對(duì)象都可用于創(chuàng)建迭代器:
迭代器對(duì)象可以使用常規(guī)for語(yǔ)句(使用迭代器協(xié)議訪問(wèn)對(duì)象)進(jìn)行遍歷:
文件對(duì)象在python中實(shí)現(xiàn)了迭代器協(xié)議,有next方法,可以很方便的訪問(wèn)文件中的內(nèi)容。
也可以自己創(chuàng)建一個(gè)迭代器,下面時(shí)筆者根據(jù)資料來(lái)創(chuàng)建的一個(gè)打印20位數(shù)值的迭代器。把類作為一個(gè)迭代器使用需要在類中實(shí)現(xiàn)兩個(gè)方法 __iter__() 與 __next__() 。
__iter__() 方法返回一個(gè)特殊的迭代器對(duì)象,在 __next__() 方法中我們可以設(shè)置在完成指定循環(huán)次數(shù)后觸發(fā) StopIteration 異常來(lái)結(jié)束迭代。
2、生成器
生成器自動(dòng)實(shí)現(xiàn)了迭代器協(xié)議。使用了 yield 的函數(shù)被稱為生成器,跟普通函數(shù)不同的是,生成器是一個(gè)返回迭代器的函數(shù)。在調(diào)用生成器運(yùn)行的過(guò)程中,每次遇到 yield 時(shí)函數(shù)會(huì)暫停并保存當(dāng)前所有的運(yùn)行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時(shí)從當(dāng)前位置繼續(xù)運(yùn)行。調(diào)用一個(gè)生成器函數(shù),返回的是一個(gè)迭代器對(duì)象。
python有兩種方法來(lái)提供生成器。
2.1 生成器函數(shù)
使用yield 語(yǔ)句而不是return返回結(jié)果。函數(shù)就是一個(gè)實(shí)現(xiàn)了迭代器協(xié)議的函數(shù),可以直接使用for來(lái)遍歷。
2.2 生成器表達(dá)式
將列表推導(dǎo)中的中括號(hào)換成圓括號(hào)就是生成器表達(dá)式。squares_list是個(gè)列表推導(dǎo),返回的是個(gè)列表。squares使用生成器表達(dá)式,返回的是個(gè)生成器對(duì)象generator object ,由于生成器自動(dòng)實(shí)現(xiàn)了迭代器協(xié)議,使用for循環(huán)迭代輸出。
生成器可以延遲計(jì)算,一次返回一個(gè)結(jié)果,而不是一次返回使用結(jié)果,對(duì)于大數(shù)據(jù)量處理十分有用。
3、裝飾器
裝飾器本質(zhì)上是個(gè)函數(shù),這個(gè)函數(shù)接收其他函數(shù)作為參數(shù)。下面是定義bread裝飾器修改say_hi函數(shù)的功能,即使用bread函數(shù)來(lái)封裝say_hi函數(shù),@是裝飾器語(yǔ)法,bread是裝飾器的名稱。
在實(shí)際應(yīng)用中,可以將重復(fù)的代碼提煉出來(lái)作為一個(gè)單獨(dú)的函數(shù),然后做成裝飾器,可以提高代碼的可讀性,代碼量也會(huì)更少,也降低后期維護(hù)代價(jià)。下面是定義的計(jì)算函數(shù)計(jì)算時(shí)間的benchmark裝飾器,然后在加法和減法函數(shù)里面使用benchmark裝飾器來(lái)封裝。
但是裝飾器的語(yǔ)法較復(fù)雜,執(zhí)行速度也較慢和難以調(diào)試。
4、上下文管理器
with 上下文管理器的作用與try/finally語(yǔ)句作用類似,在確保打開(kāi)的資源在任何情況下都能關(guān)閉。在python在python中優(yōu)先使用上下文管理器,可以用更少的代碼完成相同的功能,而且邏輯更加清除。
with語(yǔ)句的表達(dá)式返回一個(gè)對(duì)象,該對(duì)象必須有__enter__和__exit__方法。上面的第一部分打開(kāi)文件后文件對(duì)象在python中實(shí)現(xiàn)了迭代器協(xié)議,有next方法,也有__enter__和__exit__方法,可以使用 with 上下文管理器:with open('data.csv') as f 。
上下文管理器可以以一種更加優(yōu)雅的方式,操作(創(chuàng)建/獲取/釋放)資源,如文件操作、數(shù)據(jù)庫(kù)連接,并且處理異常。下面是自己定義上下文管理器,含有__enter__和__exit__方法的對(duì)象Resource。
在上面吃的例子中,寫了一個(gè)類來(lái)構(gòu)建上下文管理器。可以使用contextlib 來(lái)簡(jiǎn)化上下文管理器的邏輯,其提供了contextmanager的裝飾器,通過(guò)該裝飾器裝飾的函數(shù)就成為一個(gè)上下文管理器,可以用在with語(yǔ)句中。
在被裝飾函數(shù)里,必須是一個(gè)生成器(帶有yield),而yield之前的代碼,就相當(dāng)于__enter__里的內(nèi)容。yield 之后的代碼,就相當(dāng)于__exit__ 里的內(nèi)容。下面是自己來(lái)定義一個(gè)open_func函數(shù),使用contextmanager來(lái)裝飾成上下文管理器,yield之前的代碼時(shí)打開(kāi)文件,yield之后的代碼是關(guān)閉文件。
上面這段代碼只能實(shí)現(xiàn)上下文管理器的第一個(gè)目的(管理資源),并不能實(shí)現(xiàn)第二個(gè)目的(處理異常)。可以使用try + except+finally來(lái)實(shí)現(xiàn)異常處理。
在實(shí)際中,可能不需要except來(lái)拋出異常,只是用try + finally。下面是以前做過(guò)的將連接數(shù)據(jù)庫(kù)的功能使用contextmanager來(lái)裝飾成上下文管理器。
在上下文管理器中,with語(yǔ)句可以使用逗號(hào)隔開(kāi),同時(shí)使用多個(gè)上下文管理器。
作者:劉小白DOER
鏈接:https://www.jianshu.com/p/211276cbfd9d
來(lái)源:簡(jiǎn)書
- EOF -
回復(fù)關(guān)鍵字“簡(jiǎn)明python ”,立即獲取入門必備書籍《簡(jiǎn)明python教程》電子版
回復(fù)關(guān)鍵字“爬蟲(chóng)”,立即獲取爬蟲(chóng)學(xué)習(xí)資料

推薦
