1. 程式人生 > >第13天-迭代器和生成器

第13天-迭代器和生成器

迭代器

迭代就是重複的一個過程,但是不是單純的重複,每一次的重複都是基於上一次的結果產生的。不過只記住迭代他就是重複的執行過程就是了。

#單純的重複不是迭代,例如:
count = 0
while count < 3:
    print(count)
    count += 1

#每一次的重複都是基於上一次的結果產生的,隨著count的改變輸出不同的結果
count = 0
list = ["a", "b", "c"]
while count < 3:
    print(list[count])
    count += 1

迭代器就是迭代取數的一個工具,關鍵是我們為什麼要用迭代器呢?我們都知道python中主要的一些資料型別有整型,字串,元祖,列表,字典,集合,檔案等。對於整型而言只要一個數沒有什麼迭代器的概念,對於字串,元祖和列表我們可以通過索引去取值,但是對於字典,集合以及檔案而言,我們怎麼去像列表一樣進行取值呢?這就是迭代器引入的原因,主要就是為了不依賴與索引進行迭代取值。在python中兩個概念,一個就是可迭代物件(只要有__iter__方法的我們就稱之為可迭代物件,字串,元祖,列表,字典,集合都是可迭代物件),二是迭代器物件(不僅要有__iter__方法而且還要有__next__方法,檔案是迭代器物件),從上面的描述我們就可以看出來,迭代器物件都是可迭代的物件,但是可迭代物件卻不一定是迭代器物件。

迭代器的使用方法

dic = {'name': 'hu', 'age': 12}
iter_dic = dic.__iter__()  # 可迭代物件要變成迭代器才能夠進行使用
res = iter_dic.__next__()  # 變成迭代器之後通過__next__方法進行迭代取值
print(res)     # 對於dic迭代的值是key

當迭代器把迭代物件迴圈完畢之後會報錯

dic = {'name': 'hu', 'age': 12}
count = 0
iter_dic = dic.__iter__()  # 可迭代物件要變成迭代器才能夠進行使用
while count < len(dic):
    
try: # 當最後一個迭代完了之後會報錯,因此我們需要捕捉異常 res = iter_dic.__next__() # 變成迭代器之後通過__next__方法進行迭代取值 print(res) # 對於dic迭代的值是key except StopIteration: break

從上面的程式碼我們就可以看出來,對於迭代器的使用太過於麻煩,因此python給我們專門的設計了一個迴圈for迴圈來解決這樣的事情,for迴圈可以專門的去解決可迭代物件的問題,當然迭代器物件的問題也可以,for迴圈處理的步驟1. 把可迭代物件轉換成迭代器,(迭代器的話也會執行__iter__的方法,效果是一樣的)2. 迴圈的去呼叫__next__方法進行迭代取值。3. 通過try去捕捉異常,捕捉到異常之後停止迴圈。

# 和上面的程式碼顯示的效果是一樣的
dic = {'name': 'hu', 'age': 12}
for i in dic:
    print(i)

生成器

  生成器本質上就是迭代器,只不過這個生成器是我們自己通過yield關鍵字自己建立的迭代器而已。迭代器有兩個優點 1. 可以不依賴與索引迭代取值   2.節省記憶體。而我們建立生成器為了解決最大的問題其實就是節省記憶體。

生成器建立的規則, 通過yield關鍵字進行建立迭代器。yield和return返回的是一樣的,只是yield可以中斷函式,當我需要的時候可以重新再進行建立

def foo()
    print(1)
    yield "第一"
    print(2)
    yield "第二"

iter_foo = foo()
print(iter_foo)
next(iter_foo)

三元表示式

def max2(a, b):
    if a > b:
        return a
    else:
        return b

a = 1
b = 2

c = a if a > b else b   # 這一行資料就是上面那一個函式的簡潔的表達方式
print(c)
c = max2(a, b)
print(c)

列表生成式

l = []
for i in range(10):
    if i > 5:
        s = "egg%s" % i
        l.append(s)
print(l)

l = ["egg%s" % i for i in range(10) if i > 5]  # 這一句話和前面的幾句話都是性質是一樣的,只是簡寫了而已
print(l)

生成字典表示式

d = {}
s = [("hu", 12), ("zhou", 14)]
for k, v in s:
    d[k] = v

print(d)


d = {k : v for k, v in s} # 這個是上面幾行程式碼的縮寫
print(d)

生成器表示式

res = (i ** 2 for i in range(5))

print(res)
print(next(res))
print(next(res))
print(next(res))

練習題:

1. 編寫一個range的生成器

def my_range(start, end , step=1):
    while start < end:
        yield start
        start += step

for i in my_range(0, 10):
    print(i)
View Code

2. 求一個檔案中所包含的字元的個數,以及左右行中最大的個數

with open(r'04_多層裝飾器的聯絡.py', 'rt', encoding='utf-8') as f:
    # count = 0
    # for line in f:
    #     count += 1
    # data = f.read()
    # print(len(data))  649
    # count = 0
    # for line in f:
    #     count += len(line)
    # print(count)
    # print(sum(len(line) for line in f))
    print(max(len(line) for line in f))   # 通過生成器表示式一行寫出
View Code

3. 模擬管道,實現功能:tail -f access.log | grep '404'

# 2、模擬管道,實現功能:tail -f access.log | grep '404'

import time

def tail(file_path):
    with open(file_path, 'rb') as f:
        f.seek(0, 2)
        while True:
            # 檢視是否有新的一行加入
            line = f.readline()
            if line:
                yield line
            else:
                time.sleep(0.2)

def grep(pattern, iter_tail):
    for line in iter_tail:
        line = line.decode('utf-8')
        if pattern in line:
            yield line

for line in grep('404', tail('access.log')):
    print(line)
View Code