|
1.列表生成式(推导式列表)
通过for i in range(10)来循环0-9折10个数字,然后将每一个数字赋值给i,i在乘以2得出图中下面的结果。
a = [] for i in range(10):
a.append(i*2)
print (a)
结果是一样的
a = [i * 2for i in range(100)]
print (a)
列表生成式所生成的这些数据是会被放入到内存中的(除非删除或执行程序结束),可以随调用其中的任意数据。
print (a[10])
可以看到可以直接print (a10)来取值,能直接取值说明这个值是一直保存在内存中的,如果这个值元素的数量少到不会占很多资源,但是假如元素有一千万,一个亿时就会占用很多内存空间了。
2.生成器
c = (i * 2for i in range(100))
print (c)
可以看到,只是将中括号变成小括号后,输出的只是一个生成器,这个生成器当前没有任何的数据放在内存中,只有被调用的时候才会在内存中生成,结束后就删除内存中的元素,不调用的话就不会一直占用内存空间。
print (c[10])
可以看到使用print (c10)去引用内存中的数据并不存在,因为生成器没有被调用,所以没有任何数据元素存在内存中,所以这里会报错。
for i in c: print (i)
通过for来调用c,赋值给i,在打印i,这时候就可以看到一个个的数字被新生成
print (c10) #生成结束后我们在试着去引用c的元素,可以看到下图依然报错,这说明生成器被调用结束后,生成的元素值会在内存中删除,不会一直占用内存空间。
c = (i * 2for i in range(100))
print (c.__next__())
print (c.__next__())
print (c.__next__())
可以通过c.next()来不断的取c的下一个值,第一个值0,第二个2,以此类推来生成上一个值的下一个值。
下面我们在pycharm的python console中测试,这样取值能更方便一些
循环到50630后,这里使用了ctr+c强制停止了
然后通过c.next()可以看到,可以继续在中断值的位置继续获取下面的值。
当前已经生成了50634这个值,之前生成的值都已经没有了,被删除了,而且后面的值还没有生成,所以生成器只会记住当前的数字
可以看到生成过的数字当前并不存在,说明已经被删除掉了,生成器只记住了当前的值。
所以生成器并不会大量的去占用内存,同一时间只会存在一个值,所以有大量数据的时候,生成器是很常用的。
在3.X版本中使用next(),在2.7中使用next()
使用next()只能一个一个的去生成,所以一般都常使用for来循环生成。
3.函数定义生成器
斐波那契数列:除了第一个和第二个数外,任意一个数都可以由前两个数相加得到:
有规律,可以被推到出来的数字
print (b)下面的 a,b = b,a+b 相当于 0,1 = 1,0+1,这里的a+b的a其实是引用了while上面的b,因为当前代码并没有执行完成所以a不会是1。
前两位相加a+b=0+1,然后是1+1=2, 1+2=3, 2+3=5.....
目前还不算是一个生成器
可以看到将print改成yield 就算是一个生成器了,只有生成器可以使用 f.next()
通过next调用一次,返回一个值
可以看到for循环是继续3来之后来循环的。
这里我们并没有看到return返回的done,因为for循环无法打印函数的返回值。
不断使用next可以看到错误信息和其后面的done
在斐波那契中我们可以大概定位有多少个数字,但是如果是在其他情况和场景下,我们不知道有多少个,且我们使用next超过了这些实际的个数就会报错,比如我们在调用函数时fib(10),只赋予了10个,但是我们使用next却超过了10个,这里就会报错。
通过try一直print ('f:',x) 直到抓取到StopIteration 这个错误 将其设为别名e,然后执行该except下面的代码
StopIteration这个错误信息就是相当于通过不断的print ('f:',x) 来发现的,这个本身就代表了 上一个代码中的StopIteration:done,只不过这里将其e作为别名,而e.value,只是StopIteration:done中的这个done,所以最后打印的是Generator return value: done。
使用断点来查看步骤:
从第5步,调用函数就会返回到生成器函数,在返回之前会保留该位置,一直到第8步会将b当前的值传给第9步的x(在传之前会保留yield这个位置,保留中断状态,下次返回继续),第9步打印x,因为还没有try完成,所以到了第10步,然后11步又返回生成器函数(返回的是上次保留的位置),因为是while循环所以到了第14步,第14步又到了15步,这样后续以此类推。
yield的作用可以保留当前位置状态,将值返回出去
生成器可以实现单线程中并发(协程),速度比多线程还要快。
send与next相同,都是用来唤醒yield,只不过send还会传值
异步 |
|
|