关于python中的迭代器(Iterator)与生成器(Generator)

迭代器(Iterator):能用 next( )方法取值的对象,用 iter( )方法可以从可迭代对象(序列、生成器)中返回一个迭代器。值得 注意的是,迭代器是访问可迭代对象的一种方式,他只能往前取值,不能回取。
迭代器图解如下图所示:
在这里插入图片描述
实际上,for item in iterable 循环的本质:先通过iter( )方法获取可迭代对象iterable 的迭代器Iterator,然后对获取的可迭代对象不断用next( )方法来获取下一个item,当遇到StopIteration 的异常时结束循环,因此有:
在这里插入图片描述
说明:并不是只有for循环可以接受可迭代对象,此外还有像list( )、tuple( )等也能接收可迭代对象,比如b = list(a),这个语句不要单纯以为只是类型转换,其本质是list( )首先生成一个空列表b,然后用iter( )方法获得可迭代对象a的迭代器,然后用next( )方法依次取出a中的值然后填入到空列表b中。

可迭代对象:能用iter( )方法返回迭代器的对象,需要注意的是,可迭代对象内部需要定义iter( )方法来返回迭代器对象。常见有:字符串、列表、元组、字典、集合、字节串、字节数组等。

下面给出自定义的可迭代对象和迭代器代码(两个类实现):

from collections import Iterable
from collections import Iterator

# 可迭代对象类
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()
for i in range(3):
    classmate.add(i)
    
print(isinstance(classmate, Iterable))  # --->Ture,证明了classmate是可迭代对象
print(isinstance(classmate, Iterator))  # --->False,证明了classmate不是迭代器对象
classmate_iterator = iter(classmate)

# classmate将自动调用Classmate类中的实例方法iter(),iter()方法返回一个ClassIterator(self)
# 类对象,也即有等式成立:classmate_iterator = ClassIterator(classmate),此时的obj即为
# classmate。在for temp in classmate语句中,首先classmate类调用iter()方法返回一个
# ClassIterator类,然后ClassIterator调用next()方法,逐个取值赋给temp。

print(isinstance(classmate_iterator, Iterator))  # --->True,证明了classmate_iterator是迭代器对象
for x in classmate:
    for y in classmate:
        print((x,y),end=' ')
# --->print将输出:(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)

大家可以考虑将Classmate(object)类中的__next__()方法替换为如下函数,看看上面的输出结果将会有什么改变:

# 情形一:
def __next__(self):
    current_num = 0
    ret = self.obj.names[current_num]
    current_num += 1
    return  ret

# 情形二:
def __next__(self):
    if self.current_num < len(self.obj.names):
        ret = self.obj.names[self.current_num]
        self.current_num += 1
        return  ret

下面给出自定义可迭代对象和迭代器的代码(一个类实现):

from collections import Iterable
from collections import Iterator

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()
for i in range(3):
    classmate.add(i)
    
print(isinstance(classmate, Iterable))  # --->True,证明了classmate是可迭代对象
print(isinstance(classmate, Iterator))  # --->True,证明了classmate是迭代器对象
classmate_iterator = iter(classmate)
print(isinstance(classmate_iterator, Iterator))  # --->True,证明了classmate_iterator是迭代
                                                 # 器对象
for x in classmate:
    for y in classmate:
        print((x,y),end=' ')  # 这里将输出为:(0, 1) (0, 2)

下面给出一个高效率程序,用迭代器实现斐波那契数列的编程方法(依据迭代器的特性——用的时候才生成,大大提高了效率,节省CPU和RAM):

class Fibonacci(object):
    def __init__(self,end):
        self.ends = end
        self.current_num = 0
        self.first = 0
        self.second = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current_num < self.ends:
            self.temp = self.first
            self.first, self.second = self.second, self.first + self.second
            self.current_num += 1
            return self.temp
        else:
            raise StopIteration

fibonacci = Fibonacci(10)
for i in fibonacci:
    print(i)

生成器(Generator):一种可以简单有效的创建迭代器的工具,也可以说生成器是一种特殊的迭代器,可以用next( )或者send( )方法对其取值。
生成器的类型:生成器函数和生成器表达式。
生成器函数:一般来说,含有yield语句的函数,此函数在被调用时返回一个生成器对象,例如:range( )。
yield语句格式:yield 表达式
作用:yield语句用于def函数中,目的是将此函数作为生成器函数使用,yield用来生成数据,供迭代器的next( )方法使用。yield一个重要的应用就是,可以随时调用yield语句,那么程序会暂停,并且返回yield后面的值,一般在爬虫上应用较多。
生成器函数说明:
1,在生成器函数内调用return会产生一个StopIteration异常,不会往后执行;
2,带有yield的函数不仅仅只用于for循环中,也可以用于某个函数的参数,只要这个函数的参数是可迭代的;
3,yield是一个类似于return的关键字,迭代一次遇到yield就返回表达式的内容,并且程序会暂停至此处,直到有send( )或者是next( )方法去解等待,重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码开始执行。
4,生成器是可迭代的,但是只可以读取他一次,因为用的时候才生成,大大提高了效率,节省CPU和RAM。

生成器表达式:(表达式 for 变量 in Iterable [ if 真值表达式])
下面给出利用生成器完成斐波那契数列的代码:

def cerate_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        yield a  # 当执行到此词句时,程序暂停,首先把值a传递给num,然后当for循环继续从cerate_num取值
                 # 时,程序从yield a开始往后执行程序,而不是从头开始。
        a, b = b, a+b
        current_num += 1

generator = cerate_num(10)
for num in generator:
    print(num)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值