python生成器总结

生成器的概念

一句话解释:包含了yield关键字的函数就是生成器,它的返回值是一个生成器对象

Python 中的生成器(Generator)是十分有用的工具,它能够方便地生成迭代器(Iterator)。

创建以及使用

def my_gen():
    yield 1
    yield 2
    yield 3


gen = my_gen()

#生成器可以由next()调用
while True:
    try:
        next(gen)
    except StopIteration:
        print('Done..')
        break

#next() 调用太啰嗦,通常我们用迭代的方式获取生成器的值:
gen = my_gen()
for item in gen:
    print(item)

生成器还有一种更简单的写法,像这样: 

# 列表推导式
my_list = [x for x in range(10000)]

# 生成器表达式
my_gen  = (x for x in range(10000))

 yield的理解

1.yield相当于return。
2.函数遇到yield就暂停,保存当前信息,返回yield的值。
3.在下次执行next()时,从当前位置继续执行。

yield关键字有两点作用:
保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
将 yield 关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用 

 验证

def Fibonacci(all_nums):
    a, b = 0, 1
    current_num = 0
    print("----1----")
    while current_num < all_nums:
        print("----2----")
        yield a  # 如果一个函数中有yield语句,那么这个就不再是函数了,而是一个生成器的模板
        print("----3----")
        a, b = b, a+b
        print("----4----")
        current_num += 1
        print("----5----")
    return "done"
        
# 如果在调用Fibonacci的时候,发现这个函数中有yield,那么此时不再是调用函数,而是创建了一个生成器对象        
fib = Fibonacci(5)

ret = next(fib)
print("----6----")
print(ret)

ret = next(fib)
print("----7----")
print(ret)

ret = next(fib)
print("----9----")
print(ret)

生成器的应用

读取大文件

假如你读取大文件这样写,通常这都是没啥问题的。但如果这个文件非常非常大,那么将会得到内存溢出的报错。

def csv_reader(file_name):
    file = open(file_name)
    result = file.read().split("\n")
    return result

可以用生成器这样写

由于这个版本的 csv_reader() 是个生成器,因此你可以通过遍历,加载一行、处理一行,从而避免了内存溢出的问题。

def csv_reader(file_name):
    for row in open(file_name, "r"):
        yield row

无限序列

由于生成器一次只生成一个值,因此它可用于表示无限数据。

def all_even():
    n = 0
    while True:
        yield n
        n += 2
        
even = all_even()
for i in even:
    print(i)

优化内存

def gen():
    for x in range(10000):
        yield x

# 生成器
my_gen = gen()
# 列表
my_list = [x for x in range(10000)]

比较他们的大小

>>> import sys

>>> sys.getsizeof(my_list)
87616
>>> sys.getsizeof(my_gen)
112

 生成器组合

有时候你需要把两个生成器组合成一个新的生成器,比如:

gen_1 = (i for i in range(0,3))
gen_2 = (i for i in range(6,9))

def new_gen():
    for x in gen_1:
        yield x
    for y in gen_2:
        yield y

for x in new_gen():
    print(x)

# 输出:
# 0
# 1
# 2
# 6
# 7
# 8

这种组合迭代的形式不太方便,因此 Python 3.3 引入新语法 yield from 后,可以改成这样:

def new_gen():
    yield from gen_1
    yield from gen_2

生成器进阶语法

send()

我们除了可以使用 next() 函数来唤醒生成器继续执行外,还可以使用 send() 函数来唤醒执行。使用 send() 函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。

def gen():
    count = 0
    while True:
        count += (yield count)
>>> g = gen()
>>> g.send(None)
0
>>> g.send(1)
1
>>> g.send(2)
3
>>> g.send(5)
8

throw()

.throw() 允许用生成器抛出异常

def my_gen():
    count = 0
    while True:
        yield count
        count += 1
        
gen = my_gen()
for i in gen:
    print(i)
    if i == 3:
        gen.throw(ValueError('The number is 3...'))
        
# 输出:
# 0
# 1
# 2
# 3
# ValueError: The number is 3...

close()

.close() 可以停止生成器

def my_gen():
    count = 0
    while True:
        yield count
        count += 1
        
gen = my_gen()
for i in gen:
    print(i)
    if i == 3:
        gen.close()

结论

以上就是生成器的大致介绍了。它可以暂停控制流,并在你需要的时候随时回到控制流,从上一次暂停的位置继续执行。
生成器有助于你处理大型数据流或者表达无限序列,是生成迭代器的有用工具。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值