Python网络编程(05)----迭代器/生成器/协程(3)

本文深入探讨了Python中的协程概念,包括迭代器、生成器、yield关键字的使用,以及如何使用greenlet和gevent库实现多任务处理。通过具体案例,详细解释了Fibonacci数列的构建方法,以及如何利用yield实现任务切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、在讲解协程之前,先了解什么是Python迭代器

1)概念:迭代器是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前,不能后退。

2)特性----惰性求值:迭代器不要求你事先准备好整个迭代过程中所有的元素,仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者销毁。这个特点使其适用于遍历一些巨大或无限的集合。

3)可迭代对象:

序列:元组、列表、字符串

非序列:字典、文件

自定义类:实现了__iter__()  或  __getitem__() 方法的对象

如何判断对象是否可迭代:利用Iterable,True则表示该对象可以迭代,False表示不可以迭代。

 

4)创建迭代器对象

案例一:建立一个可以用来迭代的类,实现迭代器

# coding:utf-8
from collections import Iterable
from collections import Iterator
import time

# 如何判断一个对象是否可以迭代?  若是True,则证明可以迭代
# print(isinstance([11,22,33], Iterable))

"""目标:建立一个可以用来迭代的类,实现迭代器"""

class Classmate(object):
    def __init__ (self):
        self.names = list()
    
    def add(self,name):
        self.names.append(name)
        
    def __iter__(self):
        return ClassIterator(self)


class ClassIterator(object):
    def __init__(self,obj):
        self.obj = obj
        self.current_num = 0
        
    def __iter__(self):
        pass
    
    def __next__(self):
        if self.current_num < len(self.obj.names):
            ret = self.obj.names[self.current_num]
            self.current_num+=1
            return ret
        else:
            raise StopIteration
    
classmate = Classmate()
classmate.add("张三")
classmate.add("李四")   
classmate.add("老王")    

for name in classmate:
    print(name)
    time.sleep(1)

运行结果:

张三
李四
老王

案例二:实现类的迭代的第二种方法,上述两个类合并

# coding:utf-8

from collections import Iterable
from collections import Iterator
import time

# 如何判断一个对象是否可以迭代?  若是True,则证明可以迭代
# print(isinstance([11,22,33], Iterable))

"""目标:建立一个可以用来迭代的类,实现迭代器"""

class Classmate(object):
    def __init__ (self):
        self.names = list()
        self.current_num = 0
    
    def add(self,name):
        self.names.append(name)
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current_num < len(self.names):
            ret = self.names[self.current_num]
            self.current_num+=1
            return ret
        else:
            raise StopIteration
    
classmate = Classmate()
classmate.add("张三")
classmate.add("李四")   
classmate.add("老王")    

for name in classmate:
    print(name)
    time.sleep(1)

运行结果同上一个案例。

案例三:生成Fibonacci数列的两种方法

1)数列的形式:

a=0
b=1
num = 0
nums=list()
nums.append(a)
while num<10:
    a,b = b,a+b
    nums.append(a)
    num+=1
for i in nums:
    print(i)

运行结果:

0
1
1
2
3
5
8
13
21
34
55

2)使用迭代器实现

# coding:utf-8
# 使用迭代器方法构建 Fibonacci 数列

from collections import Iterable
from collections import Iterator
import time

"""目标:使用迭代器实现Fibonacci数列"""

class Fibonacci(object):
    def __init__ (self,all_num):
        self.all_num = all_num
        self.current_num = 0
        self.a = 0
        self.b = 1
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current_num < self.all_num:
            ret = self.a
            self.a, self.b = self.b, self.a+self.b
            self.current_num+=1
            return ret
        else:
            raise StopIteration
    
fib = Fibonacci(10)

for num in fib:
    print(num)

运行结果同上。

二、Python生成器 (yield/send)

案例一:使用生成器方法构建Fibonacci数列

# coding:utf-8
# 使用生成器方法构建 Fibonacci数列

def create_num(all_num):
    print("----1----")
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        print("----2----")
        yield a
        print("----3----")
        a, b = b, a+b
        current_num += 1
        print("----4----")


# 通过迭代器的 next() 查看生成器中的运行顺序,即 yield是暂停的一个功能
obj = create_num(10)
ret = next(obj)
print(ret)

ret = next(obj)
print(ret)

运行结果:

----1----
----2----
0
----3----
----4----
----2----
1

案例二:捕获异常(try

# coding:utf-8

# 如何通过捕获异常的情况来判断迭代的结束
def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        yield a
        a, b = b, a+b
        current_num += 1
    return "ok----"


# 通过迭代器的 next() 查看生成器中的运行顺序,即 yield是暂停的一个功能
# 使用try捕获异常
obj = create_num(10)
while True:
    try:
        ret = next(obj)
        print(ret)
    except Exception as ret:   # 判断结束
        print(ret.value)
        break

案例三:使用send启动生成器

# coding:utf-8
# 使用send启动生成器

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        ret = yield a
        print("----ret----",ret)
        a, b = b, a+b
        current_num += 1

obj = create_num(10)

ret = next(obj)
print(ret)

ret = obj.send("hahaha")
print(ret)

运行结果:

0
----ret---- hahaha
1

三、使用yield实现多任务

# coding:utf-8
# 使用yield完成多任务
import time

def task_1():
    while True:
        print("----1----")
        time.sleep(0.2)
        yield


def task_2():
    while True:
        print("----2----")
        time.sleep(0.2)
        yield

def main():
    t1 = task_1()
    t2 = task_2()
    while True:
        next(t1)
        next(t2)
        

if __name__ == "__main__":
    main()

运行结果:

----1----
----2----
----1----
----2----
----1----
----2----
----1----
----2----
----1----
----2----

四、使用greenlet实现多任务

# coding:utf-8
# 使用greenlet实现多任务

from greenlet import greenlet
import time

def test1():
    while True:
        print("----A----")
        gr2.switch()
        time.sleep(0.5)


def test2():
    while True:
        print("----B----")
        gr1.switch()
        time.sleep(0.5)

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

运行结果:

----A----
----B----
----A----
----B----

五、实现gevent实现多任务:

# coding:utf-8
# 使用gevent实现多任务

import gevent
import time

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
#         time.sleep(0.5)
        gevent.sleep(0.5)

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
#         time.sleep(0.5)
        gevent.sleep(0.5)
        
def f3(n):
    for i in range(n):
        print(gevent.getcurrent(),i)  
#         time.sleep(0.5)      
        gevent.sleep(0.5)
        
print("----1----")
g1 = gevent.spawn(f1,5)
g2 = gevent.spawn(f2,5)
g3 = gevent.spawn(f3,5)
g1.join()
g2.join()
g3.join()

运行结果:

----1----
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 0
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 0
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 0
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 1
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 1
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 1
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 2
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 2
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 2
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 3
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 3
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 3
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 4
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 4
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 4

六、使用gevent实现多任务的另外一种方法

# coding:utf-8
# 使用gevent实现多任务 (解决 time.sleep() 的问题)

import gevent
import time
from gevent import monkey
monkey.patch_all()

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        time.sleep(0.5)


def f2(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        time.sleep(0.5)
        
def f3(n):
    for i in range(n):
        print(gevent.getcurrent(),i)  
        time.sleep(0.5)      

gevent.joinall([
    gevent.spawn(f1,5),
    gevent.spawn(f2,5),
    gevent.spawn(f3,5)
])

运行结果同上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值