详细全面解释Python中的生成器和迭代器

生成器

  • 列表生成式能够生成列表,但是如果需要的列表较大,占用的内存空间就会很大,这时就会需要生成器。生成器保存了生成每个元素的计算方式,需要用时再生成某个元素,从而节省了大量的内存空间。
  • 生成器的第一种创建方式:将列表生成式最外面的中括号改为圆括号。
  • 通过next(generator_object_name)就能够每次让生成器生成一个值。下面举例说明:
>>> a = (x for x in range(10))
>>> a
<generator object <genexpr> at 0x000000886B3898E0>
>>> next(a)
0
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
  • 生成器的第二种创建方式:包含yield关键字的函数就是生成器,此时调用函数名已经不再是执行函数中的代码而是创建一个生成器对象。通过调用next(generator_object_name)来执行函数中的代码从而每次生成一个值。
  • yield关键字的作用是让函数暂停执行并返回一个值,下一次调用next()方法时就从上次yield暂停的地方继续执行,直到下一次执行yield。下面举例对第二种进行说明:
def fibonacci():
    a, b = 0, 1
    for i in range(10):
        print("----1----")
        yield b
        print("----2----")
        a, b = b, a+b
        print("----3----")


generator = fibonacci()
for x in range(3):
    v = next(generator)
    #还有一个等价的写法如下:
    #v = generator.__next__()
    print(v)
  • 运行上面代码输出内容如下。从输出结果也能够看出每次执行至yield关键字都会暂停,下次会从上次暂停的地方继续执行。
----1----
1
----2----
----3----
----1----
1
----2----
----3----
----1----
2
  • 生成器还可以用for循环进行迭代,且for循环会自动停止(不像使用next()在最后不能继续生成时会报错):
def fibonacci():
    a, b = 0, 1
    for i in range(10):
        print("----1----")
        yield b
        print("----2----")
        a, b = b, a+b
        print("----3----")


generator = fibonacci()
for x in generator:
    print(x)
  • 输出结果如下:
----1----
1
----2----
----3----
----1----
1
----2----
----3----
----1----
2
----2----
----3----
----1----
3
----2----
----3----
----1----
5
----2----
----3----
  • 生成器对象除了__next__()方法之外还有一个send()方法也能实现让生成器继续向下走一步的功能,它们的区别在于send()方法可以传入一个参数用来当做yield variable语句的返回值。下面用代码来进行解释:
def test():
    for i in range(5):
        print("----1----")
        temp = yield i
        print("----2----")
        print(temp)
        print("----3----")


t = test()
a = t.__next__()
print(a)
b = t.send("hello")
print(b)
  • 以上代码的执行结果如下。从输出结果可以看出send()语句执行是从第四行代码的赋值语句开始的,首先将传入的参数赋值给temp变量,然后再继续执行至下一次yield语句。
----1----
0
----2----
hello
----3----
----1----
1

迭代器

  • 可以用for循环取值的对象就称为可迭代对象,比如列表、字符串、元组、字典和集合等,还有一类就是生成器。
  • 判断一个对象是否是可迭代对象可以使用如下语句:
from collections import Iterable

b = isinstance("abc",Iterable)
print(b)
b = isinstance({},Iterable)
print(b)
b = isinstance([],Iterable)
print(b)
b = isinstance((x for x in range(10)),Iterable)
print(b)
b = isinstance(100,Iterable)
print(b)
  • 运行输出结果如下:
True
True
True
True
False
  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
  • 判断一个对象是否是迭代器可以使用如下语句:
from collections import Iterator

b = isinstance("abc",Iterator)
print(b)
b = isinstance({},Iterator)
print(b)
b = isinstance([],Iterator)
print(b)
b = isinstance((x for x in range(10)),Iterator)
print(b)
  • 运行输出结果如下。从结果可以看出可迭代对象不一定是迭代器,迭代器一定是可迭代对象,且生成器就是迭代器。
False
False
False
True
  • 可以使用iter()将可迭代对象转变为迭代器。
  • 一个类定义了_iter_方法和_next_方法,那么它所生成的对象就是迭代器。

猜你喜欢

转载自blog.csdn.net/gaishi_hero/article/details/81838746