列表解析和生成器之间空间和时间的对比

下面的例子从侧面也体现了,对于列表解析中for i in A , 对象A是一个数据块还是一个我们每执行一次循环求一次值,这个根本上是看A对象的next方法到底是列表解析还是返回一个generator object.

>>> def myzip(*seqs):
... 	minlen = min(len(s) for s in seqs)
... 	return ((s[i] for s in seqs) for i in range(minlen))
... 
>>> def mymap(func, *seqs):
... 	return( func(*args) for args in myzip(*seqs))
... 

>>> def test(func, *seqs):
... 	for i in mymap(func, *seqs):
... 		print(i)
... 
>>> test(pow,(1,2,3),(4,5,6))
1
32
729

>>> def test(func,*seqs):
... 	return(i for i in mymap(func,*seqs)) 
... 
>>> T=test(pow,(1,2,3),(4,5,6))
>>> T
<generator object <genexpr> at 0xb7145874>
>>> next(T)
1
>>> next(T)
32
>>> next(T)
729
>>> next(T)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

首先在myzip中执行一次for循环,它需要range(minlen)执行一次,给他个值,然后用于执行(s[i] for s in seqs);它不再是仅仅执行一次,因为我们的next是对后面的for语句而言的,现在它执行得到结果(1,4),然后args=(1,4)带入前面的pow(*(1,4))得到值为1,所以i的值就是1了。

这个流程关键是大家都必须是一个生成器,如果现在map是用返回列表解析的方式,那么你每输出一个i,mymap都是先计算出一个结果集。但具体是哪个比较快的话,我也不清楚,因为我感觉每输出一次i,Mymap 都执行一次肯定是不可能的,它肯定是就执行那一次,然后放到内存,然后每次都从这个数据块里拿i,如果数据比较少的话,我感觉还是一下子先都处理出来,然后再取比较快,因为本身你一次次的调用也挺耗费时间的。这个具体再到后面验证把。

反正通过上面的例子,如果你中途不再用generator object迭代的话,它的嵌套程序的这种逻辑也相当于没有效果了。因为你在这一个对象中,把它都处理出来了。比如下面2中的形式,当你的Mymap返回的是一个列表解析的时候,你如果要求出它的所有值,肯定嵌入的程序都得执行。


2:下面是一个改进以后程序,正好解决了我上面的疑问,他只对结果集求一次,然后让i对它进行迭代处理

其实我感觉这个是不是就是用空间换取时间的一种体现呢?

>>> def myzip(*seqs):
... 	minlen = min(len(s) for s in seqs)
... 	print('from myzip')
... 	return (print('from myzip2') or (s[i] for s in seqs)  for i in range(minlen))  #注意这里的minlen利用的又是词法闭包把它保存在当前语句的状态信息里
... 
>>> def mymap(func, *seqs):
... 	print('from mymap')
... 	return( print('from mymap2') or func(*args) for args in myzip(*seqs) )
... 
>>> def test(func,*seqs):
... 	return(i for i in mymap(func,*seqs))
... 
>>> T=test(pow,(1,2,3),(4,5,6))
from mymap
from myzip
>>> next(T)
from myzip2
from mymap2
1
>>> next(T)
from myzip2
from mymap2
32
>>> def mymap(func, *seqs):
... 	print('from mymap')
... 	return[ print('from mymap2') or func(*args) for args in myzip(*seqs)]         #把它设置成一下子处理得到结果集
... 
>>> def test(func,*seqs):
... 	return(i for i in mymap(func,*seqs))
... 
>>> T=test(pow,(1,2,3),(4,5,6))                                                       #说明它是在创建函数对象的时候,求出数据块
from mymap
from myzip
from myzip2
from mymap2
from myzip2
from mymap2
from myzip2
from mymap2
>>> next(T)                                                                           #对数据块先进行iter()调用,然后在调用next()方法
1
>>> next(T)
32


注意如果函数里面有嵌入函数的话,它会在生成当前函数对象的时候,同时对嵌入函数进行求值,这个时候如果嵌入函数返回的是一个数据块,它就是作为一个数据块,替换掉刚才所在的位置,也就是说要注意看嵌入程序的结果

下面是对map的两种输出方式,进行单独的结果显示

单独拿出嵌套函数部分,然后对它进行赋值,是一种查看它在函数对象编译结束时是一个什么情况的查看,同时也可以确定它的运行方式。

>>> mymap(pow,(1,2,3),(4,5,6))                                  #说明当它作为嵌入部分时,它最后会被下面的数据结果替换
from mymap
from myzip
from myzip2
from mymap2
from myzip2
from mymap2
from myzip2
from mymap2
[1, 32, 729]

>>> mymap(pow,(1,2,3),(4,5,6))                                  #从结果来看,它是每一次随着循环进行迭代求值
from mymap
from myzip
<generator object <genexpr> at 0xb7145964>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值