美文网首页python
python3可迭代对象、迭代器、生成器、协程yield入门

python3可迭代对象、迭代器、生成器、协程yield入门

作者: CurryCoder | 来源:发表于2019-02-22 11:21 被阅读12次
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Date    : 2019-01-24 16:13:07
    # @Author  : cdl (1217096231@qq.com)
    # @Link    : https://github.com/cdlwhm1217096231/python3_spider
    # @Version : $Id$
    
    # 1.可迭代、生成器、迭代器
    """
    可迭代对象:字符串、list、tuple、dict、deque等
    验证是否是可迭代对象、生成器、迭代器的方法,使用isinstance()方法
    """
    import collections
    from collections.abc import Iterable, Iterator, Generator
    
    # 字符串
    
    ss = "NJUST"
    print("字符串:{}".format(ss))
    print("是否是可迭代对象:{}".format(isinstance(ss, Iterable)))
    print("是否是迭代器:{}".format(isinstance(ss, Iterator)))
    print("是否是生成器:{}".format(isinstance(ss, Generator)))
    print()
    
    # list
    
    lis = [23, 'haha', "cat", 666]
    print("列表:{}".format(lis))
    print("是否是可迭代对象:{}".format(isinstance(lis, Iterable)))
    print("是否是迭代器:{}".format(isinstance(lis, Iterator)))
    print("是否是生成器:{}".format(isinstance(lis, Generator)))
    print()
    
    # 字典dict
    
    dic1 = {"Curry": "USA", "Yao": "China", "诺维斯基": "Germany"}
    print("字典:{}".format(dic1))
    print("是否是可迭代对象:{}".format(isinstance(dic1, Iterable)))
    print("是否是迭代器:{}".format(isinstance(dic1, Iterator)))
    print("是否是生成器:{}".format(isinstance(dic1, Generator)))
    print()
    # deque
    de = collections.deque("abcdefg")
    print("deque:{}".format(de))
    print("是否是可迭代对象:{}".format(isinstance(de, Iterable)))
    print("是否是迭代器:{}".format(isinstance(de, Iterator)))
    print("是否是生成器:{}".format(isinstance(de, Generator)))
    print()
    # 总结:所有的可迭代对象都不是迭代器和生成器,但都可以用for循环进行遍历;可迭代对象其内部实现了一个__iter__()魔法方法
    # 可以通过dir()方法来查看是否有__iter__()来判断一个变量是否是可迭代对象
    
    
    # 2.迭代器(与可迭代对象相比,内部函数实现仅仅多了一个__next__()函数)
    # 可以不使用for循环来获取元素,可以直接使用next()方法来实现
    """
    迭代器是在可迭代对象的基础上实现的,要创建一个迭代器,首先必须要有一个可迭代对象,所以下面是介绍如何创建一个可迭代对象,并用创建的可迭代对象创建一个迭代器。
    """
    
    
    class MyList(object):  # 定义可迭代对象类
        def __init__(self, num):
            self.end = num  # 上界
        # 返回一个实现了__iter__()和__next__()的迭代器类的实例
    
        def __iter__(self):
            return MyListIterator(self.end)
    
    
    class MyListIterator(object):  # 定义迭代器类
        def __init__(self, end):
            self.data = end  # 上界
            self.start = 0
    
        # 返回该对象的迭代器类的实例,因为自己就是迭代器,所以返回self
        def __iter__(self):
            return self
        # 迭代器必须实现的方法
    
        def __next__(self):
            while self.start < self.data:
                self.start += 1
                return self.start - 1
            raise StopIteration
    
    
    my_list = MyList(5)  # 得到一个可迭代对象
    print(isinstance(my_list, Iterable))
    print(isinstance(my_list, Iterator))
    # 迭代
    for i in my_list:
        print(i)
    my_iterator = iter(my_list)  # 得到一个迭代器对象
    print("是否是可迭代对象:{}".format(isinstance(my_iterator, Iterable)))
    print("是否是迭代器:{}".format(isinstance(my_iterator, Iterator)))
    # 迭代
    print(next(my_iterator))
    print(next(my_iterator))
    print(next(my_iterator))
    print(next(my_iterator))
    print(next(my_iterator))
    
    
    astr = "abcd"  # 创建字符串,它可以是可迭代对象
    aIterator = iter(astr)  # 通过iter()方法,将可迭代对象转化为迭代器
    print(isinstance(aIterator, Iterator))
    print(next(aIterator))
    print(next(aIterator))
    print(next(aIterator))
    print(next(aIterator))
    # 总结:迭代器其内部实现了__next__()这个魔法函数,可以通过dir()方法来查看变量是否是迭代器
    
    
    # 3.生成器generator:为了实现一个在计算下一值时不需要浪费空间的结构。生成器是在迭代器的基础上(可以使用for循环和next())再实现了yield,yield相当于函数中的return,在每次next()或者进行for循环时,都会在yield这里将新的值返回回去,并在这里阻塞,等待下一次的调用。实现节省内存,实现异步编程。
    
    # 创建一个生成器有两种方法:改进版的列表生成式和实现yield的函数
    # (1).使用改进版的列表生成式,注意不是[],而是()
    L = (x**2 for x in range(10))
    print("L是一个函数对象:{}".format(L))
    print(isinstance(L, Generator))
    print("将生成器对象转换成list进行输出:{}".format(list(L)))
    # (2).实现yield的函数
    
    
    def my_generator(n):
        now = 0
        while now < n:
            yield now
            now += 1
    
    
    gen = my_generator(10)  # 生成器对象
    print("生成器对象:%s" % gen)
    print(isinstance(gen, Generator))
    print(list(gen))
    
    # 总结:可迭代对象和迭代器,是将所有的值都生成后再存放在内存中,而生成器则是把需要的元素临时生成,节省时间与空间。
    
    # 4.运行和激活生成器
    # 由于生成器并不是一次生成所有元素,而是一次一次的执行返回,激活生成器执行的两种方法:next()和generator.send(None)
    
    
    def mygen(n):
        now = 0
        while now < n:
            yield now
            now += 1
    
    
    gen = mygen(4)
    # 通过交替执行,来说明这两种方法是等价的
    print(gen.send(None))
    print(next(gen))
    print(gen.send(None))
    print(next(gen))
    
    # 5.生成器的执行状态
    # 生成器在其生命周期中,会有4个状态:gen_created等待开始执行--->gen_running解释器正在执行(多线程应用中才能看到该状态)--->gen_suspend在yield表达式处暂停--->gen_closed执行结束
    from inspect import getgeneratorstate
    
    
    def gen(n):
        now = 0
        while now < n:
            yield now
            now += 1
    
    
    gen = gen(2)
    print(getgeneratorstate(gen))  # created
    
    print(next(gen))
    print(getgeneratorstate(gen))  # suspend
    
    print(next(gen))
    gen.close()
    print(getgeneratorstate(gen))  # close
    
    # 6.生成器的异常处理
    # 在生成器工作过程中,如果生成器不满足生成元素的条件,就会抛出异常StopIteration
    
    
    def gen1(n):
        now = 0
        while now < n:
            yield now
            now += 1
        raise StopIteration   # 抛出异常
    
    
    gen = gen1(2)
    print(next(gen))
    print(next(gen))
    # print(next(gen))
    
    # 7.从生成器过渡到协程yield
    # 在生成器暂停的时候向其发送一点东西,协程与线程有很多类似点:多个协程之间只会交叉串行执行;不同点:线程之间要频繁进行切换、加锁、解锁,从复杂度和效率上来看,比协程麻烦。协程通过使用yield暂停生成器,可以将程序的执行流程交给其他的子程序,从而实现不同子程序之间的交替执行。
    
    
    def jump_range(N):
        index = 0
        while index < N:
            # 通过send()发送的信息将赋值给jump
            jump = yield index  # yield index是将index返回给外部调用程序;jump = yield可以接收外部程序通过send()发送的信息,并赋值给jump
            if jump is None:
                jump = 1
            index += jump
    
    
    itr = jump_range(5)
    print(next(itr))
    print(itr.send(2))
    print(next(itr))
    print(itr.send(-1))
    

    参考文章链接

    python编程时光

    相关文章

      网友评论

        本文标题:python3可迭代对象、迭代器、生成器、协程yield入门

        本文链接:https://www.haomeiwen.com/subject/xdwsyqtx.html