【python基础】生成器&迭代器

singer 2019-12-29

 一、生成器:generator

  按照规则去生成一定的数据

  1、列表推导式和生成器的区别

    列表推导式: 一次性生成所有满足条件的数据
    生成器: 你要一个数据, 我生成出来给你一个

  2、生成器表达式

    生成器对象 = (表达式 for item in 容器)
    生成器对象 = (表达式 for item in 容器 if 条件)
    生成器对象 = (表达式 for item in 容器 for item2 in 容器2)

  3、通过生成器对象获取数据

    (1)next(g)   

    (2)for in 依次获取生成器对象中的每个数据    

    (3) g.__next__()

    (4)send(值):给上一次生成器函数中yield的位置传递一个值

            第一次获取生成器数据时, 不能使用send()方法获取

# 1、生成1-10的数据的生成器
g = (x for x in range(1, 11))
print(type(g))  # <class ‘generator‘>
print(g)  # <generator object <genexpr> at 0x00000000007EA948>

print(next(g))  # 1 获取g对象的数据
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 4

for x in g:
    print(x)   # 5, 6, 7, 8, 9, 10

# print(next(g))  # StopIteration


# 2、创建一个生成器对象, 包含1-10之间的所有偶数
g1 = (x for x in range(1, 11) if x % 2 == 0)

print(g1)  # <generator object <genexpr> at 0x000000000260A948>
print(type(g1))  # <class ‘generator‘>

print(g1.__next__())  # 2
print(g1.__next__())  # 4
print(g1.__next__())  # 6
print(g1.__next__())  # 8
print(g1.__next__())  # 10

# print(g1.__next__())  # StopIteration

二、生成器函数

  1、关键字yield 的作用

    1、返回一个数据,如果yield后边啥也没有,返回数据为None
    2、遇到yield获取一条数据,同时暂停函数的执行,直到下一次获取数据时,从暂停的位置继续往下执行

  2、特点  

    1、生成器函数用来生成一个生成器对象
    2、生成器函数中的代码在获取对象数据时,才会被执行

def func1():
    print("我是生成器")
    yield   # return 返回值


g = func1()
print(g)  # <generator object func1 at 0x0000000003C2CFC0>
print(type(g))  # <class ‘generator‘>

# 获取生成器对象数据的三种方式: 1, next(对象); 2,for..in 对象; 3. 对象.__next__()
print(next(g))  # 我是生成器 \n None


def func2():
    print("我是生成器")
    yield 0000


# step1: 获取生成器对象
g2 = func2()

# step2: 获取数据
print(g2.__next__())
"""
我是生成器
0
"""

# print(g2.__next__())  # StopIteration


def func3():
    print("xixi")
    yield "haha"
    print("hanhan")
    yield "daidai"


g3 = func3()

print(g3.__next__())
"""
xixi
haha
"""
print(g3.__next__())  # 三角龙
"""
hanhan
daidai
"""


def func4():
    for x in range(10):
        yield "我是第%d" % x


g4 = func4()

print(next(g4))  # 我是第0
print(next(g4))  # 我是第1
print(next(g4))  # 我是第2
print(next(g4))  # 我是第3


def func5():
    print("我是第5个生成器函数")
    child = yield "请给我xixi"
    print("taotao&huihui")
    yield child


g5 = func5()
# next(g5)  # "请给我一只食肉龙"
print(g5.__next__())  # 1. 获取一个生成器的数据
"""
    我是第5个生成器函数
    请给我xixi
"""
# TypeError: can‘t send non-None value to a just-started generator

print(g5.send("haha"))  # 2. 给生成器函数上一个yield的位置传递一个数据(霸王龙)
"""
    taotao&huihui
    haha
"""
# print(next(g5))  
# print(g5.send("abc"))  # StopIteration

三、生成器实例

# 1、传递数据, 计算所有传递的数据的总和,平均值
def func1():
    sum_num = 0  # 用来记录所有数字的和, 初始值0
    count = 0
    avg = 0  # 用来记录所有数字的平均值, 初始值0
    while True:
        num = yield (sum_num, avg)
        count += 1  # 每输入一个数据, 计数+1
        sum_num += num  # 每输入一个数据, 和累加
        avg = sum_num / count

g1 = func1()

print(g1.__next__())  # (0, 0)
print(g1.send(5))  # (5, 5.0)
print(g1.send(10))  # (15, 7.5)
print(g1.send(100))  # (115, 38,33333333)

# 2、写一个生成器, 生成斐波那契数列;
# 1, 1, 2, 3, 5, 8, 13, 21, ...
# a  b->2
#    a  b->3
def func2():
    a = 1  # 所求数的前两个数
    b = 1  # 所求数的前一个数
    while True:
        yield a  # 1, 1, 2, 3, 5,...
        a, b = b, a + b

g2 = func2()
print(g2.__next__())  # 1
print(g2.__next__())  # 1
print(g2.__next__())  # 2
print(g2.__next__())  # 3
print(g2.__next__())  # 5
print(g2.__next__())  # 8
print(g2.__next__())  # 11

四、为什么生成器是迭代器

  1、概念  

    (1)可迭代对象: 实现了__iter__方法的对象就是可迭代对象

    (2)迭代器: 实现了__iter__方法和__next__方法的对象就是迭代器

    (3)生成器:函数中使用了关键字 yield 

  2、关联

    (1)迭代器 是 可迭代对象
    (2)生成器 是 可迭代对象
    (3)生成器 是 迭代器

    __iter__()方法的返回值是 迭代器
    可迭代对象.__iter__(),就会生成一个 迭代器

  3、判断对象是否可迭代

    from collections.abc import Iterable
    isinstance(对象,Iterable)

  4、for in 的底层原理

    for in 对象
    (1)调用对象的__iter__()方法,生成一个iterator迭代器  
    (2)调用迭代器对象的__next__()方法,依次获取每个数据
    (3)for in 在遇到 StopIteration 时,停止迭代

# 写个迭代器, 传入一个范围(起始值, 终止值), 依次获取
# 这个范围中的素数


class PrimeNumber:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    # 方法: 判断一个数是不是素数
    def isPrimeNumber(self, num):  # 参数: 你要判断是不是素数的那个数
        for x in range(2, num):
            if num % x == 0:
                return False  # 返回, 函数停止执行
        return True

    def __iter__(self):  # 返回个迭代器对象: generator(迭代器)--> __iter__(), __next__()
        for x in range(self.start, self.end + 1):
            if self.isPrimeNumber(x):
                yield x

    # yield --> 生成器函数(返回值:生成器) --> 迭代器 --> __iter__()方法返回个迭代器

n3 = PrimeNumber(3, 20)
for x in n3:
    print(x)
"""
3
5
7
11
13
17
19
"""

# step1: 调用__iter__()获取迭代器 --> 生成器
# step2: 调用__next__()获取数据
# step3: StopIteration停止迭代

n4 = PrimeNumber(3, 20)
g4 = n4.__iter__()
print(g4.__next__())  # 3
g = (x for x in range(10))
print(g)  # <generator object <genexpr> at 0x0000000003C2CFC0>
print(dir(g))  # 查看g的所有方法

def func():
    yield "xixi"

g1 = func()
print(g1)  # <generator object func at 0x000000000212A548> 

print(g1.__next__())  # ‘xixi‘

相关推荐