python yield 生成器
学习python也有短时间了,最开始学习python的目的很简单,当时对web安全很感兴趣,对拿下站点权限充满无限的期望,因为在web渗透的时候很多时候都需要用脚本去爆破遍历等等,所以就去学习了python,实话实说,为了求得时间,只是匆匆学习了下基础。后面会重新深层的学过。
个人感慨略过
但是当真的去尝试融入这个安全圈子的时候,才发现自己是多么的菜,不是一般的菜,别人大佬都是初中高中就开始学习一些信安技术,但是自己入门却很晚,在大学才是真的走上了IT这一条路,这条路不知未来的路上是否充满机遇还是荆棘,但是已经选择了走这条技术的路线,那便风雨兼程。(这是句屁话,但是还得自己花时间和精力学习。)
在有次看别人写的python源码的时候,突然看了了一个yield
,而且还被语法高亮了,突然想这是啥鬼东西,怎么以前没见过,当时学的时候怎么没有学到这个。(但是内心就是那种说不出的感觉,也不想去问别人,害怕被人抛来无情的嘲笑。)无奈,百度才是最好的老师,认真的找了几篇比较好的博文资料学习了下。文章结尾,我会把这几篇博文贴出来。
在正式引出yield
关键字前,先聊一下基础,既然是基础,那我们就从最好的c语言聊起。
我们都知道一个变量是需要保存在内存中的,这里指的内存
,不是指的你的硬盘而是内存条,如果你在你些的程序中保存了很多变量到你的内存中你的内存会’炸‘掉的。当然不是真的炸,如果基础比较好的同学都知道快速排序在某种情况下,排序的效率是很快的,但是它用递归方式实现是会浪费很多的存储空间,空间复杂度是很大的。为了时间复杂度,牺牲空间复杂度在很多情况下是不可取的。
在有的时候为了节约存储空间,不把数据全放进内存中,然后再去一个一个取,那么在编程中就出现一种生成器
,迭代器
的东东。
这编程中使用则会节约我们的存储空间。
yield
原理
yield
的实现原理我接下来主要用代码例子来讲解,这样来理解更加深刻。
seq = [x*x for x in range(10)]
print(seq)
for i in seq:
print(i)
如果不知道以上代码运行的结果那么就可以自己创建一个文件,然后运行以上代码。
首先,以上代码创建了一个列表[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
,这个列表是存储在内存中的,如果现在有个需求,是要我们输出从0到100的可以得到整数算数平方根的值,当然上面代码是其中一种方式。
这里我要说一种新的方式
先看这个
def gen(n):
number = 0
result = []
while number**2 < n:
result.append(number**2)
number += 1
return result
x = gen(100)
print(x)
这是一个简单的通过把结果添加到一个列表中,然后再通过return
把结果返回。
如果我们要使用yield,则这样修改
def gen(n):
number = 0
while number**2 < n:
yield number**2
number += 1
x = gen(100)
print(x)#输出结果:<generator object gen at 0x1100d2f68> generator表示一个生成器
result1 = x.__next__() #对象x 表示一个生成器,生成器内部有__next__()方法
print(result1)
result2 = next(x) # 调用x对象内部的__next__()方法,也就是找下一个值
print(result2)
result3 = x.__next__()
print(result3)
result4 = x.__next__()
print(result4)
print('---------')
for i in gen(50):
print(i)
在python,如果一个普通函数中出现了yield
关键字,那么这个函数则就被称作生成器,有点类似在c语言中,在函数里面定义了一个static
的静态变量,在我们多次调用相应的这个函数的时候函数里面的变量是具有保存了状态的特性。
for i in gen(50):
这段代码使用的for
循环,for
循环也就是每次执行一次__next__()
方法,得到一个返回值。
如果还不是很好理解,你可以理解成这个函数gen
具有多个返回值,具有多吃返回的特性,不需要我们把很多的结果都返回,值是需要的时候一个一个生成,需要一个就取一个。(这样理解的话就知道这个为什么叫生成器了)。
当我这里讲的只是生成器的原理,在python中很多东西,都被封装成了生成器,比如我们用for
循环读取文件的时候,使用range
生成序列的时候。
这里说一下,python2
和 python3
中的range
,在python2中有:range
,xrange
两种方法生成序列:
Python 2.7.15
>>> range(12)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> xrange(12)
xrange(12)
python2
中range
则是直接返回一个列表,这样就是比较浪费内存的方式,但是xrange
的方式则好了很多,使用生成器,如果我们要使用一个很多的序列,比如;range(9999999999999)
甚至更大,那就需要浪费掉很多内存,使用xrange
则好很多
python3
中的range
则和python2
中的xrange
一样,放回的是一个生成器。
参考博文
https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
http://www.runoob.com/w3cnote/python-yield-used-analysis.html
参考视频