python协程——迭代器

迭代是访问集合元素的一种方法,迭代器是一个可以记住遍历位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不能后退。

1、可迭代对象

我们已经知道可以对listtuplestr等类型的数据可以使用for...in...的循环语法从其中一次拿到数据进行使用,我们把这样的过程成为遍历,也叫迭代
但是

(1)如何判断一个对象是否可以迭代
from collections import Iterable

print(isinstance(对象, Iterable))
# 例如:
print(isinstance([11,22,33], Iterable))     # 返回为True,则证明可以迭代
(2)构建可迭代对象
from collections import Iterable

class Classmate(object):
    def __init__(self):
        self.names = list()

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        # 如果想要对象成为一个   可迭代对象(可以使用for),那么必须实现__iter__方法
        pass

classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
print('判断classmate是否是可以迭代的对象:', isinstance(classmate, Iterable))

运行结果:

判断classmate是否是可以迭代的对象: True

可以看到,当加入__iter__方法的时候,classmate变成了一个可迭代的对象,如果去掉的话,那么classmate方法变得不可迭代,尽管其中的变量为列表,也不支持迭代。

2、构建迭代器

这里有两种方法,我将挨个解释。

(1)第一种方法:

实例
from collections import Iterator
import time

class Classmate(object):
    def __init__(self):
        self.names = list()

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        # 如果想要对象成为一个   可迭代对象(可以使用for),那么必须实现__iter__方法
        return ClassInterator(self)

class ClassInterator(object):
    def __init__(self,obj):
        self.obj = obj  # 通过实例化参数获取Classmate()对象的names属性
        self.current_num = 0

    def __iter__(self):
        pass

    # 构造迭代器,返回Classmate()对象的names属性
    def __next__(self):
        # 保证列表索引不越界的情况下,挨个返回列表names的内容
        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_interator = iter(classmate)
print('判断classmate_interator是否是迭代器:', isinstance(classmate_interator, Iterator))
for i in classmate:
    print(i)
    time.sleep(1)
原理:

迭代器的产生过程,大致可以分为:

  1. 先构造一个可迭代对象,并且在__iter__的方法中返回另一个可迭代对象,并通过self参数,传递给第二个可迭代对象自身的属性
  2. 另外的可迭代对象拥有一个__next__方法来构造一个迭代器
  3. 我们就可以对第一个可迭代对象使用for循环进行遍历
运行结果:
判断classmate_interator是否是迭代器: True
张三
李四

从输出结果也可以看出,我们成功的构造出了一个迭代器,并且通过for循环取除了names的值。

(2)第二种方法:

在第一种方法中,我们构造了两个可迭代对象来完成,构造迭代器。
其实,这里我们只需要将第一个迭代器的返回值设置为本身,并为自己添加__next__方法,同样可以完成构造迭代器

实例:
from collections import Iterator
import time

class Classmate(object):
    def __init__(self):
        self.names = list()
        self.current_num = 0

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        # 如果想要对象成为一个   可迭代对象(可以使用for),那么必须实现__iter__方法
        return self

    def __next__(self):
        # 保证列表索引不越界的情况下,挨个返回列表names的内容
        if self.current_num < len(self.names):
            ret = self.names[self.current_num]
            self.current_num += 1
            return ret
        else:
            # 在遍历取值为None时,停止遍历
            raise StopIteration

classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
classmate_interator = iter(classmate)
print('判断classmate_interator是否是迭代器:', isinstance(classmate_interator, Iterator))
for i in classmate:
    print(i)
    time.sleep(1)

运行结果:

判断classmate_interator是否是迭代器: True
张三
李四

可以看到,我们同样生成了迭代器,并且通过遍历获取值

3、迭代器的应用

我们发现迭代器最核心的功能是通过next()函数的调用来返回下一个数据值,如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是不用再将所有要迭代的数据都一次性缓存下来供后续读取,这样就可以节省大量的存储(内存)空间。

举例:

举个例子,比如,数学中有个著名的斐波那契数列(Fibonacci),数列中第一个数为0第二个数为1其后的每一个数都可由前面两个数相加得到:

0,1,1,2,3,5,8,13,21,34

现在我们想要通过for ... in ...循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以用迭代器来实现,每次迭代都通过数学计算来生成下一个数。

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

fibo = Fibonacci(10)

for num in fibo:
    print(num)

运行结果:

0
1
1
2
3
5
8
13
21
34

从运行结果的生成速度来看,有了明显的提高。

4、并不是只有for循环能接受可迭代对象

除了for循环能接受可迭代对象,list,tuple等也能接收。
比如:我们有一个list_num=[1,2,3]的列表和tuple_num = (1,2,3)的元组。

li = list(tuple_num)
print(li)
tp = tuple(list_num)
print(tp)

这里的list、tuple不是简单的类型转换,而是内部已经封装好了遍历的方法,对可迭代对象进行迭代并保存到自身开辟的内存中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值