1. 程式人生 > >python-13-迭代器,生成器,協程

python-13-迭代器,生成器,協程

列表,字典,字串,元祖都是可迭代物件(Iterable),這就意味著它們是可以使用 for迴圈 進行遍歷。
檢測是否是可迭代物件的方法 isinstance()

from collections import Iterable
result=isinstance([1,2],Iterable)
print('列表',result)
result=isinstance((1,2),Iterable)
print('元祖',result)
result=isinstance({1:'2'},Iterable)
print('字典',result)
result=isinstance('sss',Iterable)
print('字串型',result)
result=isinstance(100,Iterable)
print('int型',result)

 列表 True
 元祖 True
 字典 True
 字串型 True
 int型 False

製作一個迭代器,需要包含 iter()函式與next()函式,如下:

from collections import Iterable
class my_iterable():
    def __iter__(self):
        pass
    def __next__(self):
        pass
ii=my_iterable()
result=isinstance(ii,Iterable)
print(result)


 True

當擁有了這兩個函式,便被承認為一個可迭代物件

自定義一個迭代器

1、MyList類

class MyList(object):
# 1)初始化方法
def init

(self):

    # 定義例項屬性,儲存資料
    self.items = []

# 2)__iter__() 方法,對外提供迭代器
def __iter__(self):

    # 建立MyListIterator 物件
    mylist_iterator = MyListIterator(self.items)
    # 返回迭代器
    return mylist_iterator

# 3)addItem() 方法,用來新增資料
def addItem(self, data):
    # 追加儲存資料
    self.items.append(data)
    print(self.items)

2、自定義迭代器類:MyListIterator

class MyListIterator(object):
    # 1) 初始化方法
    def __init__(self, items):

        # 定義例項屬性,儲存MyList類傳遞過來的items
        self.items = items

        # 記錄迭代器迭代的位置
        self.current_index = 0
    # 2)迭代器方法 __iter__()
    def __iter__(self):
        pass
    # 3) 獲取下一個元素值的方法 __next__()
    # next(mylist_iterator) 就會呼叫 __next__() 方法
    def __next__(self):

        # 1、 判斷當前的下標是否越界
        if self.current_index < len(self.items):
        #     1)根據下標獲取下標對應的元素值
            data = self.items[self.current_index]
        #     2)下標位置 +1
            self.current_index += 1
        #     3)返回下標對應的資料
            return data

        #  如果越界,直接丟擲異常
        else:

            # raise 用於主動丟擲異常
            # StopIteration 停止迭代
            raise StopIteration


if __name__ == '__main__':
    # 1、建立自定義列表物件
    mylist = MyList()
    mylist.addItem("張飛")
    mylist.addItem("關羽")
    mylist.addItem("班長")
    mylist.addItem("xxxxx")

    # 遍歷
    # 1) iter(mylist) 獲取 mylist物件的迭代器  --> MyList --> __iter__()
    # 2)next(迭代器) 獲取下一個值
    # 3)捕獲異常
    # for value in mylist:
    #     print("name:", value)



    mylist_iterator = iter(mylist)
    # value = next(mylist_iterator)
    # print(value)
    #
    # value = next(mylist_iterator)
    # print(value)

3.生成器

生成器是一種特殊的迭代器,它更加便捷
建立生成器的第一種方法
1 . 列表推導式建立法(將列表推導式外面的 [] 變成())

kk=(aa*2 for aa in range(20))
2 . yeid建立

def work1():
   yield 10                          # 程式執行到yield語句的時候,程式暫停,返回yield後面表示式的值,在下一次呼叫的時候,從yield語句暫停的地方繼續執行
   yield 100
kk=work1()
value=next(kk)
print(value)

4 . 協程

從技術的⻆度來說,“協程就是你可以暫停執⾏的函 數”。如果你把它理解成“就像⽣成器⼀樣”,那麼你就想對了。

協程存在的意義:對於多執行緒應⽤,CPU通過切⽚的⽅式來切換執行緒間的執⾏,執行緒切換時需要 耗時(儲存狀態,下次繼續)。協程,則只使⽤⼀個執行緒(單執行緒),在⼀個執行緒中規定某個程式碼塊 執⾏順序
①第一種協程方式

import time
def work1():
   while True:               
    print('正在執行work1')
    yield                                        #執行大yield會暫停並儲存當前狀態,隨即去處理work2
    time.sleep(0.5)                              #加時間延遲方便觀察

def work2():
   while True:
    print('正在執行work2')
    yield                                        #執行大yield會暫停並儲存當前狀態,隨即去處理work1
    time.sleep(0.5)

if __name__ == '__main__':
    w1 = work1()
    w2 = work2()
    while True:
      next(w1)
      next(w2)

②第二種協程方式

import time
from greenlet import  greenlet
def work1():
    while True:
        print('正在執行work1')
        time.sleep(0.5)
        w2.switch()

def work2():
    while True:
        print('正在執行work2')
        time.sleep(0.5)
        w1.switch()

if __name__ == '__main__':
        w1=greenlet(work1)
        w2=greenlet(work2)
        w1.switch()

③第三種協程方式(常用重要必記)

import  time
import gevent                      #gevent 可以自動識別耗時程式碼然後切換到另一個任務
from gevent import monkey
monkey.patch_all()                 # 破解所有未識別的命令

def work1():
    while True:
        print('正在執行work1...')
        time.sleep(0.3)

def work2():
    while True:
        print('正在執行work2...')
        time.sleep(0.3)
if __name__ == '__main__':
    # 指派任務
    g1=gevent.spawn(work1)                  # gevent.spawn(函式名,引數1,引數2,引數3....)
    g2=gevent.spawn(work2)

    g1.join()      # join 阻塞,讓主程序等待協程執行。
    g2.join()