python中生成器

一.为什么要有生成器

秉着先问为什么,再问怎么做的原则,我们来看看为什么python会添加生成器这个功能。

python在数据科学领域可以说是很火。我想有一部分的功劳就是它的生成器了吧。

我们知道我们可以用列表储存数据,可是当我们的数据特别大的时候建立一个列表的储存数据就会很占内存的。这时生成器就派上用场了。它可以说是一个不怎么占计算机资源的一种方法。

二.简单的生成器

我们可以用列表推导(生成式)来初始化一个列表:

list = [x*2 for x in range(10)]
print(list)   #output:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

我们用类似的方式来生成一个生成器,只不过我们这次将上面的[ ]换成( ):

generator= (x*2 for x in range(10))
print(generator)    #output: <generator object <genexpr> at 0x000002397C0A0F68>

看到上面print(generator) 并不是直接输出结果,而是告诉我们这是一个生成器和在什么位置。那么我们要怎么调用这个generator呢。

第一种:

for item in generator:
    print(item)
#output:
0
2
4
6
8

第二种:

print(next(generator))#output:0
print(next(generator))#output:2
print(next(generator))#output:4
print(next(generator))#output:6
print(next(generator))#output:8
print(next(generator))#output:Traceback (most recent call last):StopIteration

第三种:

print(generator.__next__())#output:0
print(generator.__next__())#output:2
print(generator.__next__())#output:4
print(generator.__next__())#output:6
print(generator.__next__())#output:8
print(generator.__next__())#output:Traceback (most recent call last):StopIteration

怎么理解生成器的原理?

from collections import Iterable, Iterator
generator= (x*2 for x in range(5))
print(generator)
print(isinstance(generator,Iterator)) #判断是不是迭代器  #output:True
print(isinstance(generator,Iterable)) #判断是不是可以迭代  #output:True

用法详解
凡是可以for循环的,都是Iterable

凡是可以next()的,都是Iterator

集合数据类型如list,truple,dict,str,都是Itrable不是Iterator,但可以通过iter()函数获得一个Iterator对象

Python中的for循环就是通过next实现的:

for x in [1,2,3,4,5]:
    pass

等价于

#先获取iterator对象
it = iter([1,2,3,4,5])
while True:
    try:
        #获取下一个值
        x = next(it);
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

生成器本身就是一个迭代器

我们在内部封装好了算法,并规定好在某个条件下就返回一个结果给调用者。(x*2 for x in range(5))就是这样子实现的,并不是实现了(0,2,3,6,8)然后在一个个迭代出来,而是逐个生成。这就是为什么next(generator)可以作用了。

三、应用

1、开头说到生成器生成大量数据的时候可帮助系统节省内存。真的是这样吗?通过下面的代码感受下:

import time

def get_time(func):  #获取一段代码的运行时间
    def wraper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("Spend:", end_time - start_time)
        return result
    return wraper

@get_time
def _list(n):
    l1 = [list(range(n)) for i in range(n)]
    del l1


@get_time
def _generator(n):
    ge = (tuple(range(n)) for i in range(n))
    del ge

_list(1000)  #output:Spend: 0.029321908950805664
_generator(1000)  #output:Spend: 0.0

列表是将0-999都生成后放进一个列表里面了,所以用得时间比较多。而生成器只是封装了算法,每次调用在去调用算法,这样做就可以做到节省内存了。

2、yield 关键词

前面只告诉我们用( )来创建一个生成器。如果我们想定义一个自己的生成器函数怎么办?用return好像不行。没关系,python有yield的关键词。其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止。

def test():
    yield 1
    yield 2
    yield 3
t = test()

print(next(t))#output:1
print(next(t))#output:1
print(next(t))#output:1
print(next(t))#output:Traceback (most recent call last):StopIteration

将 “杨辉三角” 的算法封装成生成器,需要的时候去生成,这样就不会占用大量的电脑内存资源。
在这里插入图片描述

def triangle():
    _list, new_list = [], []
    while True:
        length = len(_list)
        if length == 0:
            new_list.append(1)
        else:
            for times in range(length + 1):
                if times == 0:
                    new_list.append(1)
                elif times == length:
                    new_list.append(1)
                else:
                    temp = _list[times - 1] + _list[times]
                    new_list.append(temp)
        yield new_list #返回值,然后挂起函数,等待下一次调用
        _list = new_list.copy()#调用后会继续执行下去
        new_list.clear()

n = 0
for result in triangle():
    n += 1
    print(result)
    if n == 7:
        break

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值