生成器与迭代器

本文深入探讨Python中的生成器和迭代器概念,解析生成器表达式与生成器函数yield的工作原理,以及如何区分可迭代对象与迭代器对象,为高效内存管理和循环操作提供实用指南。

01.生成器

>>>[i * i for i in range(5)]   #列表推导式
[0, 1, 4, 9, 16]

### 生成器表达式
>>>(i * i for i in range(5))
<generator object <genexpr> at 0x000001AB98F08DE0>
查看生成器对应的所有元素,有两种方式
  1. 多次调用内置函数next(),每次调用都返回生成器的下一个元素,直到抛出异常StopIteration时表示没有更多元素了。
>>>a = (i * i for i in range(5))
>>>print(next(a))
0

>>>print(next(a))
1

>>>print(next(a))
4

>>>print(next(a))
9

>>>print(next(a))
16

>>>print(next(a))
StopIteration                             Traceback (most recent call last)
<ipython-input-31-94b12d3903f7> in <module>
----> 1 print(next(a))

StopIteration: 
  1. 使用 for-in 语句对生成器进行迭代,这样就不需要关心异常StopIteration了。
a = (i * i for i in range(5))
for j in a:
    print(j)
---------------------------------
0
1
4
9
16
  • 生成器中保存的并不是其对应的所有元素,而是如何推算出所有元素的算法。将生成器用于 for-in 语句时,元素是在循环的过程中不断被推算出来的。将生成器作为内置函数 next()的实参时,返回的下一个元素也是在调用函数时被推算出来的。因此,生成器是惰性推算的,也就是说,只有当用到生成器中的某个元素时,才会临时进行推算,而并不会提前推算出来。
  • 若需要创建一个元素个数较大的容器,就可以考虑使用生成器,从而节省大量的存储空间。

生成器函数 yield

  • 上面使用类似生成式的语法得到的生成器被称为生成器表达式。此外,当推算的算法比较复杂时,还可以使用生成器函数得到生成器。
  • 生成器函数中通过关键字yield返回推算出的元素。生成器函数与普通函数的区别在于:当调用内置函数next()或使用 for-in 语句进行迭代时,执行完yield语句就会将生成器函数挂起,下次就会__从挂起的地方进行执行__。
def fib(n):
    i = 0
    a, b = 1, 1
    while i<n:
        print(a,end=',')
        a, b = b, a + b
        i +=1
fib(6)
-------------------------------------
1,1,2,3,5,8,
def fib(n):
    i = 0
    a, b = 1, 1
    while i<n:
        yield a
        a, b = b, a + b
        i +=1
fib(6)
----------------------------------
<generator object fib at 0x000001AB98DF4D68>
>>>gf = fib(4)
>>>print(next(gf))
1

>>>print(next(gf))
1

>>>print(next(gf))
2

>>>print(next(gf))
3

>>>print(next(gf))
StopIteration                             Traceback (most recent call last)
<ipython-input-47-e66ec289e8be> in <module>
----> 1 print(next(gf))

StopIteration: 
gf = fib(6)

for item in gf:
    print(item)
--------------------------------
1
1
2
3
5
8

02. 迭代器

  • 可以用于 for-in 语句的对象被称为可迭代对象。(如range、列表、元组、字符串、字典、集合、生成器)
  • 可以调用内置函数 isinstance() 判断一个对象是否是可迭代对象。标准库模块collections中的类Iterable用于表示可迭代对象。
>>>from collections import Iterable
>>>print(isinstance([1,2,3],Iterable))
True

>>>print(isinstance('abc',Iterable))
True

>>>print(isinstance((i * i for i in range(1, 7)),Iterable))
True
  • 如果一个可迭代对象可以作为内置函数next()的实参从而支持惰性推算,那么该对象被称为迭代器(Iterable)对象
  • 对于range、列表、元组、字符串、字典和集合等可迭代对象,都不可以作为内置函数next()的实参,而生成器可以。所以,生成器是迭代器的一种
  • 可以调用内置函数 isinstance() 判断一个对象是否是迭代器对象。标准库模块collections中的类Iterator用于表示迭代器对象。
>>>L = [1,2,3]
>>>next(L)
SyntaxError

>>>s = 'abc'
>>>next(s)
TypeError
from collections import Iterator

L = [1,2,3]
s = 'abc'

print(isinstance(L, Iterator))
print(isinstance(s, Iterator))
----------------------------------------------
False
False
>>>print(isinstance((i * i for i in range(1, 7)), Iterator))
True

可以调用内置函数 iter() 把不支持惰性推算的可迭代对象转换成迭代器对象

iter_L = iter(L)
iter_s = iter(s)

print(isinstance(iter_L, Iterator))
print(isinstance(iter_s, Iterator))
--------------------------------------------------
True
True
>>>print(next(iter_L))
1

>>>print(next(iter_L))
2

>>>print(next(iter_L))
3

>>>print(next(iter_L))
StopIteration: 
>>>print(next(iter_s))
a

>>>print(next(iter_s))
b

>>>print(next(iter_s))
c

>>>print(next(iter_s))
StopIteration: 

如果一个对象同时实现了特殊方法__iter__()__next__(),那么该对象也被称为迭代器对象。如果将该对象用于 for-in 语句, for-in 语句首先会调用特殊方法 __iter__()返回一个可迭代对象,然后不断调用该可迭代对象的特殊方法__next__()返回下一次迭代的值,直到遇到StopIteration时退出循环。

class MyIterator(object):
    def __init__(self):
        self.data = 0
        
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.data > 5:
            raise StopIteration()
        else:
            self.data += 1
            return self.data


for item in MyIterator():
    print(item)
--------------------------------------------
1
2
3
4
5
6
class Fib(object):
    def __init__(self):
        self.a, self.b =0, 1
        
    def __iter__(self):
        return self
    
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 50:
            raise StopIteration()
        return self.a
    
for item in Fib():
    print(item)
----------------------------------------------------------------
1
1
2
3
5
8
13
21
34

for-in 语句在默认情况下不能用于自定义类对象的实例对象

  • 若想让 for-in 语句可以用于自定义类对象的实例对象,必须在自定义类对象中实现特殊方法__iter__()__next__()。 for-in语句首先会调用特殊方法__iter__()返回一个可迭代对象,然后不断调用可迭代对象的特殊方法__next__()返回下一次迭代的值,直到遇到StopIteration时退出循环。
  • 只实现了特殊方法__iter__()的类对象,被称为可迭代类对象;同时实现了特殊方法__iter__()__next__()的类对象,被称为迭代器类对象。
  • 之所以 for-in 语句可以用于某些内置函数(如List、tuple、str等)的实例对象,是因为这些内置类对象中都同时实现了特殊方法__iter__()__next__()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值