【Python】帮你理解可迭代对象、迭代器和生成器

版权声明:欢迎交流,转载请注明出处。 https://blog.csdn.net/u013034226/article/details/82390725

目录

一.前言

二.从for说起

三.再讲一下可迭代对象和迭代器

①iterable object(可迭代对象):

②iterator object(迭代器):

③迭代器的应用场景

四.为什么要来到“生成器”?

①迭代器生成斐波那契数列       

②生成器生成斐波那契数列

③应用情景

参考文献:



借用一位大佬的话:“yield” is your friend!

一.前言

最近学习了迭代,但是对于迭代以及迭代器,生成器的原理、作用,还是有点蒙,通过在网上查找相关知识和自己总结,写了这篇博客,实在是狗尾续貂。

相信大家和我有一样的疑问,为什么要探索python中的迭代机制?会用for不就可以了吗?在继续下去之前,需要回答一下这个问题。for语句非常好用,就像是国民老公王思聪一样,可以处理各种迭代问题。但是,国民老公是一个标配,他可能并不适合每一个女生。既然标配的不合意,一种替代方法就是自己定制,比如更加幽默,或更有情怀等等。这就是我们探究迭代机制的原因。当for循环不能满足我的要求,我需要一个自己的迭代方式,这个时候你就需要探究一下迭代背后的机制。

二.从for说起

对于一个简单的语句:

for i in [1, 2, 3, 4, 5]:
print(i)

背后发生了什么呢?首先,python解释器会判断[1, 2, 3, 4, 5]这个列表是不是可以迭代的,也就是这个列表是不是一个iterable object,如果用户输入的是一个iterable object,那么python解释器会首先把这个iterable object转换成一个iterator object,也就是迭代器。

 三.再讲一下可迭代对象和迭代器

①iterable object(可迭代对象):

在类里面提供__iter__方法,保证创建的对象是可迭代对象,如下代码:

from collections import Iterable


# 自定义可迭代对象
class MyList(object):

    def __init__(self):
        # 定义列表属性保存用户添加的数据
        self.my_list = list()

    # 添加数据的方法
    def append_data(self, data):
        self.my_list.append(data)

    # 在类里面提供__iter__方法,那么保证创建的对象是可迭代对象
    def __iter__(self):
        # 可迭代对象的本质: 是通过迭代器帮助可迭代对象依次迭代对象中的每一个数据
        # 真正完成获取数据的操作是通过迭代器完成的
        pass

# 通过自定义可迭代类型创建自定义可迭代对象
my_iterable = MyList()

# 查看my_iterable是不是指定类型:Iterable
result = isinstance(my_iterable, Iterable)
print(result)


#结果是True

直到现在,真正的迭代仍然没有开始。真正的迭代不是作用在iterable object上,而是作用在迭代器上。从这一点,也可以认为,迭代器是更底层的东西。iterable object是我们人类喜欢的东西,而迭代器iterator则是python解释器喜欢的东西。 

②iterator object(迭代器):

虽然定义了可迭代对象,但是要想获取数据则需要迭代器来完成;在类中提供__iter__和__next__

方法,创建的对象就是迭代器对象。代码如下:

from collections import Iterable
from collections import Iterator


# 自定义可迭代类
class MyList(object):

    def __init__(self):
        # 定义列表属性保存用户添加的数据
        self.my_list = list()

    # 添加数据的方法
    def append_data(self, data):
        self.my_list.append(data)

    # 在类里面提供__iter__方法,那么保证创建的对象是可迭代对象
    def __iter__(self):
    my_iterator = MyIterator(self.my_list)
    return my_iterator


# 自定义迭代器类
class MyIterator(object):

    def __init__(self, current_list):
        # 保存外界传入过来的数据对象
        self.current_list = current_list
        # 记录获取数据的下标
        self.current_index = 0

    def __iter__(self):
        return self

    # 使用__next__方法获取指定对象中的数据
    def __next__(self):
        # 判断下标是否越界
        if self.current_index < len(self.current_list):
            # 根据下标获取数据对象中的指定数据
            value = self.current_list[self.current_index]
            # 获取数据成功对下标加上1
            self.current_index += 1
            return value
        else:
            # 代码执行到此说明下标越界,停止取值操作,抛出停止迭代异常
            raise StopIteration

# 通过自定义可迭代类创建出自定义可迭代对象,添加数据
my_iterable = MyList()
my_iterable.append_data(1)
my_iterable.append_data(2)

for value in my_iterable:
    print(value)

        迭代器有的标配就是__iter__和__next__方法,每个迭代器都有,这种方法是自从它被创建出来的时候就有。iter()函数表示获取可迭代对象的迭代器,会调用可迭代对象身上的__iter__方法,next()函数表示获取迭代器对象中下一个值,会调用迭代器对象身上的__next__方法。真正的迭代是由__next__来执行的,也就是__next__每次从迭代器中取出一个元素来操作,直到所有的元素被取完。——这里不过多赘述

③迭代器的应用场景

如果我们要取一个有规律数列当中的一个值(包括大家学习过的斐波那契数列),假设我要取第10000个斐波那契数,看图 ↓

四.为什么要来到“生成器”?

迭代器简单粗暴,生成器则高冷优雅。

①迭代器生成斐波那契数列       

# 迭代器完成斐波那契数列
class Fibonacci(object):
    def __init__(self, num):
        # num:表示根据个数生成数列
        self.num = num
        # 保存斐波那契数列前两个值
        self.first = 0
        self.second = 1
        # 记录生成斐波那契数列的下标
        self.current_index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current_index < self.num:
            result = self.first
            self.first, self.second = self.second, self.first + self.second
            # 生成数据完成以后对下标加上1
            self.current_index += 1
            return result
        else:
            # 表示数列生成完成
            raise  StopIteration
# 创建生成斐波那契数列的对象
fib = Fibonacci(5)
for i in fib:
    print(i)

②生成器生成斐波那契数列

# 生成器完成斐波那契数列
def fibonacci(num):
    # num:表示生成器根据个数创建指定个数的fibonacci数列
    first = 0
    second = 1
    current_index = 0
    # 循环判断条件是否成立,表示是否生成斐波那契数列
    while current_index < num:
        result = first
        first, second = second, first + second
        current_index += 1
        yield result

generator1 = fibonacci(4)
for a in generator1:
    print(a)

可见生成器属于轻装版的迭代器,但生成器仍然是迭代器,不过是改进的。

 生成器的第一个特殊之处是它的定义方式。对于生成器函数,我们一般需要自己定义。生成器函数的定义方式和普通函数几乎一样,只不过它有一个yield语句。当函数执行到yield的时候,该函数被挂起,等待下次被next()激活。至于用法,迭代器和生成器一样。它们的区别主要体现在定义的方式上。

③应用情景

range()函数会返回一个迭代器,如果用生成器呢?

def my_range(start, end, step):
    x = start
    while x < end:
        yield x
        x += step

new_range = my_range(0, 10, 1)


for a in new_range:
    print(a)


###
0
1
2
3
4
5
6
7
8
9
###

希望这些可以帮助大家更好的理解迭代器和生成器。

参考文献:

有很多内容参考了网上的各种资料,其中一位作者的文章读后似醍醐灌顶,在这里把他的个人主页地址附上

作者:time
主页:https://www.douban.com/note/641787208/ 

猜你喜欢

转载自blog.csdn.net/u013034226/article/details/82390725
今日推荐