python生成器及应用场景

2023-05-16

概念:

      生成器是一个特殊的程序,可以被用作控制循环的迭代行为,是一边循环一边计算的机制,称为generator 。

生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

使用场景:

        由于可以使用生成器很方便地实现一个迭代器,因此迭代器适用的场景生成器几乎都适用。

  • 节省内存
  • 流式处理数据
  • 无限的数据

1.实现generator的两种方式

第一种方法:把一个列表生成式的[]改成(),就创建了一个generator

#列表生成式
lis = [x*x for x in range(10)]
print(lis)
#生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
 
# 结果:
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# <generator object <genexpr> at 0x000002A4CBF9EBA0>

  创建list和generator_ex的区别是什么呢?

         从表面看就是[  ]和(),但是结果却不一样,一个打印出来是列表(因为是列表生成式),而第二个打印出来却是<generator object <genexpr> at 0x000002A4CBF9EBA0>,

      如何打印出来generator_ex的每一个元素呢?

#生成器
generator_ex = (x*x for x in range(10))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
结果:
0
1
4
9
16
25
36
49
64
81
Traceback (most recent call last):
 
  File "列表生成式.py", line 42, in <module>
 
    print(next(generator_ex))
 
StopIteration

可以看到,generator保存的是算法,每次调用next(generaotr_ex)就计算出他的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误,而且上面这样不断调用是一个不好的习惯,正确的方法是使用for循环,因为generator也是可迭代对象:

#生成器
generator_ex = (x*x for x in range(10))
for i in generator_ex:
    print(i)
     
结果:
0
1
4
9
16
25
36
49
64
81

所以我们创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代,并且不需要关心StopIteration的错误,

第二种方式:在函数中使用yield关键字,函数就变成了一个generator。

                     调用函数就是创建了一个生成器(generator)对象。

def positive(limit):
    n = 1
    while n <= limit:
        yield n
        n += 1

for n in positive(5):
    print(n)

获取 迭代器 的元素时要通过 next 方法,而 yield 关键字的作用就在于在每次执行 next 方法时执行到 yield 的位置返回值同时退回到 next 调用的位置继续执行。

2 yield from 关键字

# yield from 后面接一个 可迭代对象 ,等价于用 for in 去单独 yield。
list1 = [1, 2, 3, 4]
list2 = ['a', 'b', 'c', 'd']

def my_gen_1():
    yield from list1
    yield from list2

def my_gen_2():
    for n in list1:
        yield n

    for n in list2:
        yield n

print('my_gen_1 循环结果:', [x for x in my_gen_1()])
print('my_gen_2 循环结果:', [x for x in my_gen_2()])


# my_gen_1 循环结果: [1, 2, 3, 4, 'a', 'b', 'c', 'd']
# my_gen_2 循环结果: [1, 2, 3, 4, 'a', 'b', 'c', 'd']

3 send 方法实现数据的双向通信

通过 yield 向生成器外部传值,实际上我们也可以向生成器内部传值

def double_money():
    print('请输入你的金钱,我来负责乘2,(机会只有三次)')

    # 需要先执行一次 send(None) 到这里
    x = yield
    x = yield x * 2
    x = yield x * 2
    x = yield x * 2

double = double_money()

# 必须先执行一次 send None
# 执行到第一个 yield 关键字
double.send(None)

print(double.send(10))
print(double.send(20))
print(double.send(30))

"""
请输入你的金钱,我来负责乘2,(机会只有三次)
20
40
60
"

def average_gen():
    count = 0
    n = yield
    while True:
        count += 1
        n += yield n / count

av = average_gen()

av.send(None)
print(av.send(10))
print(av.send(20))
print(av.send(30))


"""
10.0
15.0
20.0
"""


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python生成器及应用场景 的相关文章

随机推荐