python中的迭代器和生成器

迭代器

实现__next__方法

如果一个类实现了__next__方法,那么这个类的对象是一个迭代器
例如:

class myRange:
    def __init__(self,start=0,end=5):
        self.start=start
        self.end=end
    def __next__(self):
        self.start+=1
        if self.start>self.end:
            raise StopIteration
        return self.start

此时类myRange的一个实例对象就是一个迭代器,所谓迭代,就是利用next,一个一个的读取迭代器里面的值,直到终止条件抛出StopIteration异常为止。
在这里插入图片描述

实现__iter__方法

需要注意的是,上面定义的类myRange目前不是可迭代对象,不可以直接在循环中迭代的,例如:
在这里插入图片描述
我们需要实现__iter__方法才使得myRange类是可以在循环中迭代的
在这里插入图片描述

利用迭代器的设计方法构造自己的迭代器

我们已经知道,只要设计好__next__和__iter__,就可以构造迭代器了.
我们以range函数举例,
range函数返回的是一个可迭代序列,而且可以利用list函数直接得到序列
在这里插入图片描述

我们现在就构造自己的range函数

class myRange:
    def __init__(self,*params):
        self.stride=1
        assert type(params)==tuple
        if len(params)==0:
            raise TypeError("range expected 1 arguments, got 0")
        if len(params)>3:
            raise TypeError("range expected at most 3 arguments, got %d"%len(params))
        assert len(params)>=1 and len(params)<=3
        #上面的代码判断边界条件
        if len(params)==1:
            #仅仅传进来一个值,那么这个值就做为终止位置
            end_value=params[0]
            self.start=0
            if end_value<=0:
                self.end=0
            else:
                self.end=end_value
        elif len(params)==2:
            #传进来两个值
            start_value,end_value=params
            if start_value>=end_value:
                self.start=0
                self.end=0
            else:
                self.start=start_value
                self.end=end_value
        else:
            assert len(params)==3
            start_value,end_value,stride=params
            if stride==0:
                raise ValueError('range() arg 3 must not be zero')
            elif (start_value<end_value and stride<0) or start_value==end_value:
                self.start=0
                self.end=0
            else:
                #start_value<end_value stride>0
                #start_value>end_value stride<0
                self.start=start_value
                self.end=end_value
                self.stride=stride
        self.start-=self.stride
        self.end-=self.stride
                
    def __next__(self):
        assert self.stride!=0
        if self.stride>0:
            if self.start>=self.end:
                raise StopIteration
            self.start+=self.stride
            return self.start
        else:
            if self.start<=self.end:
                raise StopIteration
            self.start+=self.stride
            return self.start
            
    def __iter__(self):
        return self

打印验证结果:
在这里插入图片描述

生成器

生成器可以简单的理解为包含有yield语句的函数,生成器返回的其实就是一个可迭代的迭代器。这个迭代器里面的数据每当返回一个的时候,迭代器就会被“冻住”,固定在那个位置,下次再次迭代的时候,迭代器会从上一次定住的那个点的位置开始执行

举个例子
在这里插入图片描述

我们可以看到,这10000000个数并不是在内存中的,只有当迭代generator(generator其实是一个可迭代的迭代器)的时候,才会返回出来一个结果,而且这个结果返回后就被丢弃了

我们再举一个例子,创建可以展平列表元素的生成器:

在这里插入图片描述
这里面需要注意的是,对于数字来说上面的代码是没有问题的,因为数字是不可迭代的对象,所以是有终止条件的,然而假如列表中含有字符串,我们要知道

  • 第一,字符串是可迭代的对象,我们不希望一个字符一个字符的输出,而是希望整体输出字符串,那么就不能迭代字符串
  • 第二,python中即使是单个字符也是字符串,所以会陷入到无穷递归中

在这里插入图片描述
解决办法是添加isinstance判断一下数据类型,如果是字符串,那么就直接yield
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值