2021-12-25 Python-20

初学时,被可迭代对象,迭代器和生成器绕的云里雾里。
首先来区分一下这几个概念。

迭代器(iterator)

迭代器是指内部包含了 iternext 方法的类。
iter 函数返回对象本身,而 next 方法则是返回下一个元素。

#依次输出迭代器中的元素
class An_Iterator(object):
    def __init__(self,data):
        self.data=data
        self.index=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == len(self.data):
            raise StopIteration
        value=self.data[self.index]
        self.index += 1
        return value

string=An_Iterator('abc')
next(string)  #也可以写作 string.__next__() 得到元素 'a'
next(string)  # 'b'
next(string)  # 'c'
next(string)  # 抛出异常 StopIteration

在上面的代码块中,先创建了 An_Iterator 的类,内部有个iter的方法,返回对象本身。当访问内部的next方法时,返回下一个元素。当超出了范围后,返回异常。
实际上满足下面两个条件的都可以称为迭代器
(1)iter() 方法返回迭代器对象本身。
(2)next() 方法会返回下一个迭代器对象。如果数据没有了,抛出 StopIteration 异常。

for i in string:
    print(i)

一般不用next方法来返回,可以用 for 循环来遍历循环。在 for 语句的幕后,其实 python 先对对象调用了 iter 函数。这个函数返回了迭代器对象,这边也就是返回了本身。返回的对象能够使用 next 方法,调用下一个元素。

生成器(generator)

生成器是一种特殊的迭代器,也含有iternext方法。

生成器的构造

生成器可以通过2种方法进行构造。
(1) 将函数定义中的 return 变成 yield,即可定义一个生成器
每次语句执行到 yield 时,就跳出了定义的函数。下一次再执行,则从上次中断的地方继续执行。所以在迭代生成器时,每一次执行都可以保留上一次的状态,而不是像普通方法那样,遇到 return 就返回结果,下一次执行只能再次重复上一次的流程。

def squares(n=10):
'''返回1:n^2'''
    for i in range(1,n+1):
        yield i**2

a=squares(3) #此处并未执行squares中的代码,只是创建了一个生成器对象
next(a) #1
next(a) #4
next(a) #9

for element in a:
    print(element,end=' ')
#1 4 9

再看下一个例子,更深入理解 yield 的用法。

def counter_generator(low, high):
    while low <= high:
       yield low
       low += 1

for i in counter_generator(5,10): 
    print(i, end=' ')

# 5 6 7 8 9 10

在 while 循环中,当它到达 yield 语句时,将返回 low 值,并退出生成器。在第二次下一次调用期间,发生器在之前中断的地方恢复,然后low+1。再继续使用 while 循环,并再次进入 yield 语句。

之前提到生成器和迭代器都有iternext方法,可以通过dir() 函数查看。

dir(string)
dir(a)
#能在输出的列表中找到__iter__和__next__方法

生成器最大的好处就是能够处理很大的数据而不占用很大内存, 因为它是一边计算一边生成元素的,而不是一下子把所有的元素都导入到内存中,所以大大节省了内存,理论上可以产生包含无限元素的生成器。
(2)生成器表达式
在列表表达式中,以中括号的形式来创建,生成器表达式只要把中括号替换成小括号即可。

gen=(x**2 for x in range(10))
for i in gen:
    print(i)

生成器有一个问题就是不能重复使用,当执行完上面的代码后,再执行依次,不会有内容输出。

可迭代对象(Iterable)

可迭代对象有iter方法,能够返回一个迭代器。

#还是上面这样一个迭代器
class An_Iterator(object):
    def __init__(self,data):
        self.data=data
        self.index=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == len(self.data):
            raise StopIteration
        value=self.data[self.index]
        self.index += 1
        return value
class It(object):
    def __init__(self,data):
        self.data=data
    def __iter__(self):
        return An_Iterator(self.data)

b=It('abcd') #b是一个可迭代对象
dir(b) #输出中,b包含了__iter__,而没有__next__方法   

上述的代码中,定义了一个 An_Iterator 的迭代器,定义了 It 类,这个类包含了iter方法,并且返回了迭代器An__Iterator,符合可迭代的对应,b是 It 的一个实例化, 所以b是可迭代对象。
在 python 的数据结构中,字符串,tuple,list,dict,set均为可迭代对象,而文件对象是迭代器对象。
对可迭代对象,也可以通过for循环遍历,但是不能使用next方法
因为 for 语句执行过程中,先将对象使用iter方法,这时候就返回一个迭代器,而迭代器自然可以用next方法。

判断迭代器和可迭代对象

from collections.abc import Iterable,Iterator
list_1=[1,2,3]
isinstance(list_1,Iterable) #True
isinstance(list_1,Iteration) #False

从上面的结果也可以看到,列表是可迭代对象,而不是迭代器。

参考:
15分钟彻底搞懂迭代器、可迭代对象、生成器【python迭代器】_哔哩哔哩_bilibili

你可能感兴趣的:(2021-12-25 Python-20)