Python列表生成器

本篇将介绍python生成器,更多内容请参考:python学习指南

前言

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅访问前面几个元素,那后面绝大多数占用的空间都白白浪费了。
python生成器是用来代替"不一定能够使用全部元素的数组",等到使用某一元素时,才生成该元素,用来节省空间.

生成器创建方式

第一种:

在前面我们介绍python列表生成式,这里我们只需要把列表生成式的[]改成(),就创建了一个generatro

>>>L = [x * x for x in range(10)]
>>>L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>g = (x*x for x in range(10))
>>>g
<generator object <genexpr> at 0x1022ef630>

创建Lg的区别仅在于最外层的[](),L是一个list,而g是一个generator
上面表达式中我们可以直接列出list(L)的每一个元素,但我们打印g的时候,却打印了g的类型,那么,我们如何打印generator的每一个元素呢?
如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>>next(g)
0
>>>next(g)
1
>>>next(g)
4
>>>next(g)
9
>>>next(g)
16
>>>next(g)
25
>>>next(g)
36
>>>next(g)
49
>>>next(g)
64
>>>next(g)
81
>>>next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,知道计算出最后一个元素,没有更多元素时,抛出StopIteration的错误。
这样不断调用next(g)实在是太变态了,生成器是可迭代对象

>>>from collections import Iterable  #载入模块
>>>isinstance(g, Iterable)  #生成器是可迭代对象吗?
True

这样,知道用什么来了吧?
当然是使用强大的for...in迭代来实现

>>>g = (x * x for x in range(10))
>>>for n in g:
    print(n)
0
1
4
9
16
25
36
49
64
81

通过for迭代的方式来循环生成器,并不用关心StopIteration的错误。

使用关键字 yield 关键字

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现

斐波那契数列生成器

def creatNum():
    print("---开始执行生成器方法---")
    a,b = 0,1
    for i in range(0,5):
        print("--step1--")
        yield b
        print("--step2--")
        a,b = b,a+b
        print("--step3--")
    print("--stop--")

print("直接调用方法...")
print(creatNum())

#这里用一个标识符来指向生成器(不要把creatNum()当做函数)
func = creatNum()

#使用for循环来执行生成器
for i in func:
    print(i)
输出结果: (执行完毕不会崩溃)

#直接调用方法...
<generator object creatNum at 0x101c30f10>
---开始执行生成器方法---
--step1--
1
--step2--
--step3--
--step1--
1
--step2--
--step3--
--step1--
2
--step2--
--step3--
--step1--
3
--step2--
--step3--
--step1--
5
--step2--
--step3--
--stop--

在执行生成器时,可以使用 生成器.send(param) 方法
send方法不光是执行一步next操作,还会把send里面的参数传到生成器中充当yield表达式的返回值

def test():
    i = 0
    while i < 5:
        temp = yield i
        print(temp)
        i += 1

t = test()

#先使用next执行,看能出来什么结果
t.__next__()
t.__next__()
print(t.__next__())

#使用send执行
t.send("1231231231223123")
print(t.send("hahahahhahaha"))
输出结果: (可见next输出temp为none , 而send 则把值传递进了生成器)

None
None
2
1231231231223123
hahahahhahaha
4

参考

  1. python生成器是怎样工作的
  2. Python中的yield关键字
  3. python生成器
  4. 廖雪峰-生成器
posted @ 2018-01-17 14:13 小破孩92 阅读(...) 评论(...) 编辑 收藏