python基础____学习笔记15 (迭代器和生成器)

一、迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式,是一个可以记住遍历的位置的对象。
实现了方法__iter__的对象是可迭代的对象,而实现了方法__next__的对象是迭代器, 像序列和字典 都是可迭代的,因为他们都实现了__iter__方法。

1.1 创建一个迭代器
一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
 __iter__()  方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__()  会返回下一个迭代器对象。
例子:
创建一个字符串列表,每个元素从'hello-10' 到 'hello-50' ,步长为2

class MyNumbers:
    def __init__(self,prefix,startindex,endindex,step):
        self.prefix=prefix
        self.startindex = startindex
        self.endindex = endindex
        self.step = step

    def __iter__(self):
        self.a=self.startindex
        return self
    def __next__(self):
        if self.a <= self.endindex:
            x = self.a
            self.a += self.step
            return self.prefix+str(x)
        else:
            raise StopIteration

myclass = MyNumbers('hello',10,50,2)
myiter = iter(myclass)
mylist = []
for x in myiter:
    mylist.append(x)
print(mylist)

因为MyNumbers实现了__iter__、__next__,所以可以直接通过 list() 函数将,生成列表

myclass = MyNumbers('hello',10,50,2)
mylist=list(myclass)
print(mylist)

1.2  iter() 和next()

迭代器有两个基本的方法:iter() 和 next()
字符串,列表或元组对象都可用于创建迭代器:

list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
print(next(it))   # 输出迭代器的下一个元素
print(next(it))   # 输出迭代器的下一个元素
class MyNumbers:
    def __init__(self,prefix,startindex,endindex,step):
        self.prefix=prefix
        self.startindex = startindex
        self.endindex = endindex
        self.step = step

    def __iter__(self):
        self.a=self.startindex
        return self
    def __next__(self):
        if self.a <= self.endindex:
            x = self.a
            self.a += self.step
            return self.prefix+str(x)
        else:
            raise StopIteration

myclass = MyNumbers('hello',10,50,2)
myiterobj=iter(myclass)
print(next(myiterobj))
print(next(myiterobj))

二、生成器
根据自己制定规则循环生成数据,当条件不成立时则生成数据结束。数据并不是一次性全部生成处理,而是使用一个,再生成一个,这样可以节约大量的内存。
生成器有2中创建方式:
          yield 表达式
          生成器推导
2.1 yield 表达式
生成器是包含关键字yield的函数,但被调用时不会执行函数体内的代码,而是返回一个迭代器。每次请求值时,都
将执行生成器的代码,直到遇到yield或return。 yield意味着应生成一个值,而return意味着生成器应停止执行。

def MyNumbers(prefix,startindex,endindex,step):
    x = startindex
    while x <=endindex:
        yield prefix + str(x+step)
        x = x +step

mylist = []
mygenerator=MyNumbers('hello-',10,50,2)
for x in mygenerator:
    mylist.append(x)
print(mylist)

代码执行到 yield 会暂停,然后把结果返回出去,下次启动生成器取值时会在暂停的位置继续往下执行 

同样也可以使用 mylist=list(MyNumbers) 生成列表

2.2  生成器推导式:
与列表推导式类似,只不过生成器推导式使用小括号

mylistgenerator = ('hello-'+str(x) for x in range(10,50,2))
print(mylistgenerator) #<generator object <genexpr> at 0x000001D8F0AE6C48>

#mylist=list(mylistgenerator)
mylist =[]
for x in mylistgenerator:
    mylist.append(x)

print(mylist)

可使用next 函数获取生成器中的下一个值,for 循环遍历生成器中的每一个值

三、生成器方法
生成器方法主要有三种:

send:  yield 向外界提供一个值,同样外界可以向生成器发送一个值,该值位于 yield 左边
throw: 在生成器函数执行暂停处,抛出一个指定的异常,之后程序会继续执行生成器函数中后续的代码,直到遇到下一个 yield 语句。如果到剩余代码执行完毕没有遇到下一个 yield 语句,则程序会抛出 StopIteration 异常。
close:  在生成器函数暂停的地方抛出一个 GeneratorExit 异常

3.1 send
 

def MyNumbers(prefix,startindex,endindex,step):
    x = startindex
    while x <=endindex:
        y = yield prefix + str(x+step)
        x = x + step
        print(f'Get string:{y}')

mylist = []
mygenerator=MyNumbers('hello-',10,50,2)

onestring= mygenerator.__next__()          #第一次取值后, 停留在   yield prefix + str(x+step) 即 yield 'hello-' + str(10+2),  onestring为 hello-12
print(mygenerator.send(onestring))         #send 发送后,执行 y='hello-12' ; x=x+2 ; print(f'Get string:{hello-12}') ; yield prefix + str(x+step) 即  yield 'hello-' + str(12+2); 返回了 'hello-14'
onestring= mygenerator.__next__()          #此时__next__相当于执行了 send(None). y = none ; x=x+2;  print(f'Get string:{None}');  yield prefix + str(x+step) 即 yield 'hello-' + str(14+2); 返回了 'hello-16'
print(mygenerator.send(onestring))         #send 发送后,执行 y='hello-16' ; x=x+2 ; print(f'Get string:{hello-16}') ; yield prefix + str(x+step) 即  yield 'hello-' + str(16+2); 返回了 'hello-18'

通过调用 next()或者 __next__() 方法,可以实现从外界控制生成器的执行。send() 方法可带一个参数,也可以不带任何参数(用 None 表示)。其中,当使用不带参数的 send() 方法时,它和 next() 函数的功能完全相同。

3.2 close方法

def MyNumbers(prefix,startindex,endindex,step):
    x = startindex
    while x <=endindex:
        try:
            yield prefix + str(x+step)
            x = x + step
            
        except GeneratorExit :
            print('生成器结束')
            break


mylist = []
mygenerator=MyNumbers('hello-',10,50,2)

onestring= mygenerator.__next__()
print(onestring)
onestring= mygenerator.__next__()
print(onestring)

mygenerator.close()

     在while 循环异常处理必须加上break 跳出循环,否则循环再一次走到 yield prefix + str(x+step), 此时生成器已经关闭,将产生RuntimeError异常
    异常这代码中不能再包含 yield 语句,否则程序会抛出 RuntimeError 异常。 也无法再调用 next()函数或者 __next__() 方法启动执行,否则会抛出 StopIteration 异常。

3.3 throw方法
generator.throw(type[, value[, traceback]])

def MyNumbers(prefix,startindex,endindex,step):
    x = startindex
    while x <=endindex:
        try:
            yield prefix + str(x+step)
            x = x + step

        except ZeroDivisionError:
            print('捕获到了 异常 ZeroDivisionError')
        except GeneratorExit :
            print('生成器结束')
            break


mylist = []
mygenerator=MyNumbers('hello-',10,50,2)

onestring= mygenerator.__next__()
print(onestring)
onestring= mygenerator.__next__()
print(onestring)

print(mygenerator.throw(ZeroDivisionError))

onestring= mygenerator.__next__()
print(onestring)

mygenerator.close()


#生成器结束

从  yield prefix + str(x+step) 处发送了异常,此时返回时 是上次的值 hello-14, 此时暂停在这里.
当 执行最后的onestring= mygenerator.__next__(),  将继续执行x=x+step; while x<=endindex;  yield prefix + str(x+step) 此时 取得hello-16, 最后关闭生成器

四、总结
可以直接作用于for循环的数据类型有以下几种:
      一类是集合数据类型,如list,tuple,dict,set,str等
      一类是generator,包括生成器 和带yield的generator function

可以直接作用于for 循环的对象统称为可迭代对象:Iterable
可作用于next()函数的对象都是Iterator类型;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
通过iter函数将可迭代对象转换为迭代器

可以使用isinstance()判断一个对象是否为可Iterable对象

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值