设为首页 加入收藏

TOP

关于 Python的生成器浅析(一)
2018-10-06 21:35:01 】 浏览:182
Tags:关于 Python 成器 浅析

生成器可以理解为一种的数据结构,将算法保存,每次计算并返回一个结果,实现了迭代器协议,生成器也是迭代器


生成器有两种表现形式,1)生成器表达式;2)生成器函数


1、生成器表达式


说到生成器表达式,就得先说一下列表推导式  [i for i in range(10)]  ,生成器表达式,就是将 [ ]  改为 (),区别如下所示


>>> b = [i for i in range(20)]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]


>>> b = (i for i in range(20000))
>>> b
<generator object <genexpr> at 0x00000185EC6104F8>
>>> next(b)
0
>>> next(b)
1
>>> next(b)
2


生成器表达式优点:省内存,一次只计算返回一结果。 缺点:不知道有几个元素,只能往后遍历,不能向前遍历,且只能整个生成器只能遍历一次


列表推导式优点:可以通过下标获取元素。 缺点:占用内存大


2、生成器函数


生成器函数:在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数


我们都知道 return 是函数的返回值,yield 也可以将值返回,我们先看一个简单的生成器函数与普通函数之间的差别


>>> def test():
...    print("_______生成器函数")
...    yield "返回值1"
...    yield "返回值2"
...    yield "返回值3"
...
>>> test()
<generator object test at 0x000001651BEC0570>
>>> t1 = test()
>>> print(t1.__next__())
_______生成器函数
返回值1
>>> print(t1.__next__())
返回值2
>>> print(t1.__next__())
返回值3
>>> print(t1.__next__())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


可以看到在第7行调用test()函数的时候,并没有执行函数,而是返回了一个生成器对象。在第10行执行 t1.__next__() 才真正的执行了函数,返回 "返回值1",并保存当前的生成器函数的状态。


每执行一次 next(),生成器函数将执行到下一 yield 并将相应的结果返回,直到产生StopIteration异常。


理解了上述过程,就不难理解生成器表达式的原理,next(t1)  等价于  t1.__next__()


def test():
    for i in range(10):
        yield i


print(test())
t2 = test()
print(next(t2))
print(next(t2))
print(next(t2))


t3 = (i for i in range(10))
print(t3)
print(next(t3))
print(next(t3))
print(next(t3))


#输出结果
<generator object test at 0x000001A12D8FF570>
1
<generator object <genexpr> at 0x000001A12D8FF5E8>
1


3、生成器强调,send()


生成器中还有一个重要的方法  send() 方法,send()  方法可以解决将值传递给生成器函数的问题,具体如下:


>>> def test():
...    print("____start_____")
...    y1 = yield "返回1"
...    print("____生成器函数内:%s" % y1)
...    y2 = yield "返回2"
...    print("____生成器函数内:%s" % y2)
...    yield "返回3"
...
>>>
>>> t1 = test()
>>> print(t1.__next__())
____start_____
返回1
>>> print(t1.send("a"))
____生成器函数内:a
返回2
>>> print(t1.send("b"))
____生成器函数内:b
返回3


在这里第一次获取值的时候,不能用send(),否者会报错,如果一定要用send,则传值None,如下:


>>> t2 = test()
>>> t2.send("a")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> t3 = test()
>>> t3.send(None)
____start_____
'返回1'


对于send()  不是很理解的可以尝试往下看,下边是我的一些个人理解,不是很准确,我觉得这样会比较好理解一些


我们可以把函数内 第3行  y1 = yield "返回1"  看成两个过程:1)yield "返回1"    2)y1 = receive_from_send()  [并没有这个方法,只是为了理解说明]


这样就可以看到,当执行 send() 时将参数"a" 传递给生成器函数,并在 1)过程停留,传递过去的值没有语句接收,则会出错


所以第一次是不能传值给生成器函数,y1接收到的值为下一次遍历遍历生成器接收的值。


这里也可以也可以在,上上边的代码执行流程可以看出,执行了 14行,y1才会接收到值。


补充一点:每执行一次 1)next(),2)__next(),3)send(),都会在yield语句停留,并保存当前状态,知道直到产生StopIteration异常,结束遍历。


通过生成器,

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python 字符串的格式化两种方式 下一篇深入理解 Python 迭代器

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目