一、什么叫生成器?

Python中,一边循环一边计算的机制,称为生成器:generator

二、怎么创建生成器

1.生成器表达式()
生成器表达式返回一个生成器对象,需要用一个变量名来接收
g = (x*3 for x in range(5))
# 打印g,返回一个生成器对象
print(g) # <generator object <genexpr> at 0x000002125FA1DA50>


2.生成器函数
def generation():
    print('hello1')
    yield 1
    print('hello2')
    yield 2
    print('hello3')
    yield 3
        
gg = generation()
# 打印gg,返回一个生成器对象
print(gg) # <generator object generation at 0x000002125FA1D740> :函数未立即执行,返回一个生成器对象

next(gg) # 返回hello1, 调用next(gg)或gg.next()方法函数执行,遇到‘yield’函数执行停止
next(gg) # 返回hello2, 调用next(gg)或gg.next()方法函数执行,遇到‘yield’函数执行停止
next(gg) # 返回hello3, 调用next(gg)或gg.next()方法函数执行,遇到‘yield’函数执行停止 
next(gg) # 返回StopIteration
说明:从上面可以看到‘generation’函数没有使用return作为返回值,而是使用了yield作为返回值。
      一个带有yield作为返回值的函数为生成器函数。当我们使用yield时,它帮我们自动创建了__iter__()
      和next()方法,在没有数据时,会抛出stopIteration异常。
简述函数执行过程:
a.调用函数generation(),返回一个生成器对象
b.第1次使用next(gg),函数开始执行,返回hello1,遇到yield关键字,函数停止执行,并记录当时执行的位置'1'
c.第2次使用next(gg),函数从'1'处,开始执行,返回hello2,遇到yield关键字,函数停止执行,并记录当时执行的位置'2'
d.第3次使用next(gg),函数从'2'处,开始执行,返回hello3,遇到yield关键字,函数停止执行,并记录当时执行的位置'3'
e.第4次使用next(gg),函数从'3'处,开始执行,但是3后面没有语句了此时会抛出异常‘StopIteration’ 

从上面可以看到写4个next(gg),可不可以不写这么多?
答:可以,可以用for循环来代替
for i in gg:
    print(i)
# i的返回值,当使用for循环对迭代器对象进行循环时,会返回yield的返回值
hello1
1
hello2
2
hello3
3

 

三、什么叫迭代器?

在 Python 中,迭代器是实现迭代器协议的对象,它包含方法 __iter__() 和 __next__()

创建迭代器

要把对象/类创建为迭代器,必须为对象实现 __iter__() 和 __next__() 方法。

正如 Python 类/对象 ,所有类都有名为 __init__() 的函数,它允许您在创建对象时进行一些初始化。

__iter__() 方法的初始化迭代器对象。

__next__() 方法进行迭代

class MyNumbers:
  def __iter__(self):
    self.a = 1  # 初始化
    return self  # 返回迭代器对象本身   

  def __next__(self):
    x = self.a
    self.a += 1  # 迭代
    return x

myclass = MyNumbers()  # 实例化对象,创建命名空间
myiter = iter(myclass)  # 使用iter方法进行迭代

print(next(myiter))  # 1
print(next(myiter))  # 2
print(next(myiter))  # 3
print(next(myiter))  # 4
print(next(myiter))  # 5

 

Python 迭代器的好处

使用迭代器的好处是可以节省资源。

  • 代码减少。
  • 代码冗余得到极大解决。
  • 降低代码复杂度。
  • 它为编码带来了更多的稳定性。

 

 四、可迭代对象

可以实现iter方法,可以用for…in…进行遍历的对象

可以使用python内置数isinstance()来判断一个对象是否属于可迭代对象

from typing import Iterable
# 列表
a = isinstance([1, 2, 3], Iterable)
print(a)  # True

# 字符串
b = isinstance('1', Iterable)
print(b)  # True

# 整数
c = isinstance(1, Iterable)
print(c)  # False

# 元组
d = isinstance((1, 2, 3), Iterable)
print(d)  # True

# 字典
e = isinstance({'name': 'anna'}, Iterable)
print(e)  # True

# 集合
f = isinstance({'age'}, Iterable)
print(f)  # True

列表、字符串、元组、字典、集合都是可迭代对象,而整数不是可迭代对象

 

注意:可迭代对象不是迭代器 

 下面将可迭代对象转化为迭代器

from typing import Iterable, Iterator

l1 = ['name', 'age', 'sex']
a = isinstance(l1, Iterable)  # 判断对象是否为可迭代对象
aa = isinstance(l1, Iterator)  # 判断对象是否为迭代器
print(a)  # True
print(aa)  # False

'''
根据迭代器定义,迭代器使用__iter__()方法初始化迭代器对象,使用__next__()方法进行迭代;
而可迭代对象只实现了__iter__()方法,但是没有实现__next__()方法,所以不是迭代器
'''
可以使用iter()方法将可迭代对象转化为迭代器
iterator_a = iter(l1)
print(type(iterator_a),isinstance(iterator_a, Iterator))  # <class 'list_iterator'> , True

 

 结论:每个迭代器都是可一迭代的,可以迭代的对象不一定是迭代器