Python學習之三大名器-裝飾器、迭代器、生成器

程式設計師啟航發表於2019-09-21

一、裝飾器

裝飾,顧名思義就是在原來的基礎上進行美化及完善,器這裡指函式,所以說裝飾器就是裝飾函式,也就是在不改變原來函式的程式碼及呼叫方式的前提下對原函式進行功能上的完善。其核心原理其實是利用閉包。

格式 @關鍵字+裝飾函式

被裝飾函式()

注意:@行必須頂頭寫而且是在被裝飾函式的正上方

按照形式可以分為:無參裝飾器和有參裝飾器,有參裝飾器即給裝飾器加上引數

以下示例是一個無參裝飾器,為原函式新增了統計執行時間的功能

import time
#定義裝飾器 
def timer(func):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print("run time is %s" %(stop_time-start_time))
        return res
    return wrapper
#呼叫裝飾器
@timer
def index():
    l = []
    for i in range(10000000):
        l.append(i)
#呼叫階段 
index()

以下是一個有參裝飾器,實現簡單的認證功能,#數字表示程式依次執行順序

def auth2(auth_type): #1 #3
    def auth(func): #4 #6
        def wrapper(*args,**kwargs): #7 #10
            if auth_type == 'file': #11
                name=input('username: ')
                password=input('password: ')
                if name == 'zhejiangF4' and password == '666':
                    print('auth successfull')
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('auth error')
            elif auth_type == 'sql': #12
                print('nothing!') #13
        return wrapper #8
    return auth #5
@auth2(auth_type='sql') #2
def index():
    print('welcome to inex page')
 index() #9

二、迭代器

迭代器(iterator)是一種物件,它能夠用來遍歷標準模板庫容器中的部分或全部元素,每個迭代器物件代表容器中的確定的地址**。———百度百科**

可迭代的:只要物件本身有 iter方法,那它就是可迭代的

執行物件下的 iter方法,得到的結果就是迭代器如果你依然在程式設計的世界裡迷茫,不知道自己的未來規劃可以加入我們的Python秋秋裙去784掉758文214字看看前輩們如何學習的!交流經驗!自己是一名高階python開發工程師,從基礎的python指令碼到web開發、爬蟲、django、資料探勘等,零基礎到專案實戰的資料都有整理。送給每一位python的小夥伴!分享一些學習的方法和需要注意的小細節

為什麼要用迭代器:
優點
1:迭代器提供了一種不依賴於索引的取值方式,這樣就可以遍歷那些沒有索 引的可迭代物件了(字典,集合,檔案)
2:迭代器與列表比較,迭代器是惰性計算的,更節省記憶體

    **缺點:
1:無法獲取迭代器的長度,使用不如列表索引取值靈活
2**:**一次性的,只能往後取值,不能倒著取值**

檢視s物件是否是迭代器:print(isinstance(s,Iterator)) 返回True就是迭代器

from collections import Iterable,Iterator
s='hello'
l=[1,2,3]
t=(1,2,3)
d={'a':1}
set1={1,2,3,4}
f=open('a.txt')
s.__iter__()
l.__iter__() 
t.__iter__()
d.__iter__()
set1.__iter__()
f.__iter__()
print(isinstance(s,Iterable))
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(set1,Iterable))
print(isinstance(f,Iterable))
print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(d,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))

執行結果如下:

可以看出,字串、列表、字典、集合、元組、檔案都是可迭代的,但是隻有檔案是迭代器

三、生成器

通過列表生成式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。

所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為生成器:generator。

函式中包含yield語句的我們稱其為生成器函式

yield與return有何區別?
return只能返回一次函式就徹底結束了,而yield能返回多次值
yield到底幹了什麼事情:
yield把函式變成生成器(生成器就是迭代器)
函式在暫停以及繼續下一次執行時的狀態是由yield儲存

下例是兩個生成器的應用,一個用來不斷的輸入url,不斷的解析,另外一個則模仿Linux中的管道命令(實質是將一個函式的執行結果傳給下一個函式做處理,實現的比較簡單粗暴,多包涵,哈哈)

例1:

from urllib.request import urlopen
def get(url):
    while True:
        def index():
            return urlopen(url).read()
        url = yield index()
g = get('http://www.baidu.com')
next(g)
def run():
    while True:
        url = input("請輸入URL:")
        if 'http://' not in url:
            print(g.send('http://'+url))
        else:
            print(g.send(url))
run()

例2:

def cat(filename):
    with open(filename,'r') as f:
        while True:
            line = f.readline()
            if not line:
                break
            else:
                yield line
def grep(string,lines):
    for line in lines:
        if string in line:
            yield line
g1 = cat('a.txt')
g2 = grep('mac',g1)
if __name__ == '__main__':
    m = input("請輸入命令:").strip()
    if m == "cat a.txt |grep mac":
        for i in g2:
            print(i)

補充:協程

如果在一個函式內部yield的使用方式是表示式形式的話,如x=yield,那麼該函式成為協程函式

直接看例子吧

def hello(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        next(res)
        return res
    return wrapper
@hello
def eater(name):
    print('%s start to eat food' %name)
    food_list=[]
    while True:
        food=yield food_list
        print('%s get %s ,to start eat' %(name,food))
        food_list.append(food)
    print('done')
e=eater("somebody")
print(e.send('巧克力'))
print(e.send("香蕉"))

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913713/viewspace-2657830/,如需轉載,請註明出處,否則將追究法律責任。

相關文章