python学习之---生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含1000万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

要创建一个generator,有很多种方法。

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

1. 简单的列表操作:

1 >>> list1 = [x*x for x in range(10)]
2 >>> list1
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4 >>> list2 = [2*x for x in range(12)]
5 >>> list2
6 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
7 >>> 

2. 生成器操作:

1 >>> list3 = (x*x for x in range(10))
2 >>> list3
3 <generator object <genexpr> at 0x7f302fdb6cd0>
4 >>> list1
5 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
6 >>> list2
7 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
8 >>> 

如代码所示,list1和list2是一个列表,而list3是一个generator,在任意时刻我们可以随便打印出list1和list2的列表元素,但是我们怎么才可以打印出list3的元素呢?,在这里generator提供一个打印自身元素的函数,next()。

 1 >>> list3
 2 <generator object <genexpr> at 0x7f302fdb6cd0>
 3 >>> list3.next()
 4 0
 5 >>> list3.next()
 6 1
 7 >>> list3.next()
 8 4
 9 >>> list3.next()
10 9
11 >>> list3.next()
12 16
13 >>> list3.next()
14 25
15 >>> list3.next()
16 36
17 >>> list3.next()
18 49
19 >>> list3.next()
20 64
21 >>> list3.next()
22 81
23 >>> list3.next()
24 Traceback (most recent call last):
25   File "<stdin>", line 1, in <module>
26 StopIteration
27 >>> 

generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

使用next方法虽然可以计算出生成器的值,但是,实在是太不人性化了,在此,还有没有更好的方法来输出生成器的值呢?方法肯定是有的,那就是采用for迭代输出:

 1 >>> list4 = (x*x for x in range(10))
 2 >>> list3
 3 <generator object <genexpr> at 0x7f302fdb6cd0>
 4 >>> for n in list4:
 5 ...     print n
 6 ...
 7 0
 8 1
 9 4
10 9
11 16
12 25
13 36
14 49
15 64
16 81
17 >>> 

所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。

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

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

 1 >>>
 2 >>> def fibla(max):
 3 ...     n,a,b = 0,0,1
 4 ...     while n < max:
 5 ...         print b
 6 ...         a,b = b,a+b
 7 ...         n = n + 1
 8 ...
 9 >>> fibla(8)
10 1
11 1
12 2
13 3
14 5
15 8
16 13
17 21
18 >>> 

观察之后发现,fibla函数其实是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

 1 >>> def fibla(max):
 2 ...     n,a,b = 0,0,1
 3 ...     while n < max:
 4 ...         print b
 5 ...         a,b = b,a+b
 6 ...         n = n + 1
 7 ...
 8 >>> fibla(8)
 9 1
10 1
11 2
12 3
13 5
14 8
15 13
16 21
17 #上下对比
18 >>> def fibla(max):
19 ...     n,a,b = 0,0,1
20 ...     while n < max:
21 ...         yield b
22 ...         a,b = b,a+b
23 ...         n = n +1
24 ...
25 >>> fibla(8)
26 <generator object fibla at 0x7f302fd5ca00>
27 >>> 

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

 1 >>> def fibla(max):
 2 ...     n,a,b = 0,0,1
 3 ...     while n < max:
 4 ...         yield b
 5 ...         a,b = b,a+b
 6 ...         n = n +1
 7 ...
 8 >>> fibla(8)
 9 <generator object fibla at 0x7f302fd5ca00>
10 >>> for x in fibla(8):
11 ...     print x
12 ...
13 1
14 1
15 2
16 3
17 5
18 8
19 13
20 21
21 >>> 
时间: 2024-08-08 01:27:59

python学习之---生成器的相关文章

python学习之生成器yield

python学习之生成器yield **yield的作用是使函数生成一个结果序列而不是一个值,任何使用yield的函数都称为生成器,调用生成器会创建一个对象,该对象通过连续调用next()或者__next__()方法生成结果序列** 一般情况 >>> def count(n,m): >>> print('这是一个循环外部测试') >>> while n>0: >>> print('这是一个循环内部测试') >>>

Python学习二(生成器和八皇后算法)

看书看到迭代器和生成器了,一般的使用是没什么问题的,不过很多时候并不能用的很习惯 书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个ugly的代码 def table(m, lst): '''绘制m列的棋盘,每行有个皇后旗子''' head = '┌' + '─┬' * (m-1) + '─┐' row = lambda x: '│' + ' │' * x + '╳│' + ' │' * (m - x - 1) trow = '├' + '─

python学习之生成器(generator)

生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象 生成器分类及在python中的表现形式:(python有两种不同的方式提供生成器)1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果.yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行 def triangles(): a=[1] while True: yield a a=

Python 学习笔记 -- 生成器

#定义一个生成器,形式与函数相同,区别在于yield关键字,它其实类似于return def easyYield(): yield 1 yield 2 #将生成器实例化一个对象,绑定在变量身上,通过next取得yield的内容 a = easyYield() print(next(a)) print(next(a)) #第二个实例,升级版的生成器 def libs(): a,b=0,1 while True: a,b = b,a+b yield a for each in libs(): if

Python学习之三大名器-装饰器、迭代器、生成器

Python学习之三大名器-装饰器.迭代器.生成器 一.装饰器     装饰,顾名思义就是在原来的基础上进行美化及完善,器这里指函数,所以说装饰器就是装饰函数,也就是在不改变原来函数的代码及调用方式的前提下对原函数进行功能上的完善.其核心原理其实是利用闭包.     格式 @关键字+装饰函数          被装饰函数()      注意:@行必须顶头写而且是在被装饰函数的正上方     按照形式可以分为:无参装饰器和有参装饰器,有参装饰器即给装饰器加上参数     以下示例是一个无参装饰器,

Python学习之旅—Day07(生成器与迭代器)

前言 本篇博客主要专注于解决函数中的一个重要知识点--生成器与迭代器.不管是面试还是工作,生成器与迭代器在实际工作中的运用可以说是非常多,从我们第一天开始学习for循环来遍历字典,列表等数据类型时,我们就已经和生成器,迭代器打交道了!本篇博客从最基础的基本概念,例如容器,可迭代对象,生成器,迭代器的概念,到for循环是怎么工作的娓娓道来.希望本篇博客能够帮助大家切实掌握生成器与迭代器的使用与底层原理. 一.容器 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in

Python学习之路-装饰器&生成器&正则表达式

装饰器 通俗的讲,装饰器就是在不改变源代码基础上,给源代码增加新功能. 不改变函数的源代码.调用方式.返回值等,给函数增加新功能. 经典案例:登录装饰器, def login_decorator(func):     def inner():         if USER_TEMP["status"] == False:             print("\033[31;1m用户未登录,请先登录\033[0m")             login_atm()

Python学习---装饰器/迭代器/生成器的学习【all】

Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210 原文地址:https://www.cnblogs.com/ftl1012/p/9484145.html

Python学习-39.Python中的生成器

先回顾列表解释 1 lista = range(10) 2 listb = [elem * elem for elem in lista] 那么listb就将会是0至9的二次方. 现在有这么一个需求,需要存储前10个斐波那契数到硬盘. 那么先写产生斐波那契数的函数: 1 def fib(max): 2 n,a,b = 0,0,1 3 while n < max: 4 print(b) 5 a,b = b,a + b 6 n+=1 这样就会打印出前max个斐波那契数了.接着我们再修改一下.(因为我