设为首页 收藏本站
查看: 674|回复: 0

[经验分享] Python之迭代器和生成器

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-12-2 09:03:49 | 显示全部楼层 |阅读模式
Python 迭代器和生成器
  

迭代器
  Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string、list、tuple)进行迭代,还可以对不是序列,但表现出序列行为的对象进行迭代,例如字典键、文件的行。
  迭代器对象有一个next()方法,调用后返回下一个条目。所有条目迭代完后,迭代器引发一个StopIteration异常告诉程序循环结束。for语句可用于序列类型,也可以用于迭代器类型,它会在内部调用next()并捕获异常。
  不过,迭代器也有一些限制,它不能向后移动,不能回到开始,也不能复制一个迭代器。
  iter(obj)工厂函数可以返回一个迭代器,reversed()函数返回一个反序访问的迭代器,
  例如:



t = (123, 'xyz', 45.67)
it = iter(t)    # it = reversed(t) 函数返回一个反序访问的迭代器
it.next()       # 123
it.next()       # ‘xyz’
it.next()       # 45.67
it.next()       # StopIteration
  
  iter()方法的另一种使用方式是:iter(func, sentinel),它会重复调用func,直到迭代器的下个值等于sentinel。



a = 1
def foo():
global a
print(a)
a += 1
return a
it = iter(foo, 11)
for i in it:
pass
  上面的例子中,for循环会在i=11的时候停下来。
  
  我们知道,for语句接受可迭代对象(序列或迭代器)作为其参数,每次迭代其中一个元素。它会自动调用迭代器的next()方法,捕获StopIteration异常并结束循环,而这一切都是在内部发生的。例如:



for c in "hello world" : print c
  
  上面是通过序列项迭代元素,下面介绍一种使用range函数进行序列索引迭代的方法。
  range函数返回一个list,它有三种调用形式:



range(start, end, step)
range(start, end) # step = 1
range(end)     # start=0, step=1
  例如:



for eachVal in range(2, 19, 3):
print "value is: ", eachVal
  
  注意,当有有一个很大范围的列表时,xrange()可能更为适合,因为它不会在内存里创建列表的完整拷贝,它只能被用在for循环中,在for循环外使用没有意义。
  另外,xrange()返回的是一个xrange对象,这既不是一个序列对象,也不是一个迭代器对象。
  xrange()的用法跟range()完全一样:



for eachVal in xrange(2, 19, 3):
print "value is: ", eachVal
  但xrange不会返回一个list,而是每次循环返回一个值,性能更好些,后面会介绍生成器表达式,也是类似的原理。
  
  另外,在迭代可改变对象的时候不要修改它们。



lst = range(10)
print(lst)
for ele in lst:
ele = ele*3
print(lst)
  可以发现,lst没有任何改变。
  如果要修改迭代的对象,可以使用索引迭代:



lst = range(10)
print(lst)
for k in range(len(lst)):
lst[k] = lst[k]*3
print(lst)
  
  

列表解析
  列表解析的语法:
  [expr for iter_var in iterable if cond_expr]
  返回一个列表。
  例如:



seq = [1, 2, 3, 4 ,5, 6, 7, 8, 9]         
[item for item in seq if item%2]      
# [1, 3, 5, 7, 9]
  
  又比如打印一个3*5的矩阵:



[(x+1, y+1) for x in range(3) for y in range(5)]
  

生成器表达式
  生成器表达式与列表解析的用法一样,只是把"[]"换成了 “()”,但生成器表达式返回不是list,而是生成器(generator),生成器本质上是一种函数。
  生成器在每次计算出一个条目后,把这个条目yield出来,它使用了一种延迟计算(lazy evaluation),所以在内存上更有效。
  例如:



>>> matrix = ((x+1, y+1) for x in range(3) for y in range(5))   
>>> for i in matrix: print(i)
...
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(3, 5)
  
  再比如,如果想得到一个很大的文本文件最长的行:



max( len(line.strip()) for line in open('/etc/motd') )
  如果这里使用列表解析,那么不可避免需要把整个文件的所有行都加载到内存中,而是要生成器表达式在性能上会更好。
  

生成器
  生成器的本质是一个带yield语句的函数,通常一个函数只能返回一次,而生成器能暂停执行并返回一个中间的结果(yield语句的功能),返回一个值给调用者并暂停执行。当生成器的next()方法被调用的时候,它会准确地从离开地方继续。
  可见,生成器跟协程的概念很类似,可以暂停或者挂起,并从程序离开的地方继续执行。
  



rows = [1, 2, 3, 17]
def cols():
yield 56
yield 2
yield 1
x_product_pairs = ((i,j) for i in rows for j in cols())
for pair in x_product_pairs:
print(pair)
  运行结果:



(1, 56)
(1, 2)
(1, 1)
(2, 56)
(2, 2)
(2, 1)
(3, 56)
(3, 2)
(3, 1)
(17, 56)
(17, 2)
(17, 1)
  
  当调用生成器的next()方法时,生成器会执行,直至出现yield语句,并把yield的参数返回给调用者(类似于return)。
  注意,yield语句后面的代码不会再运行。需要下次继续调用next()方法才会继续执行,直至函数退出。
  此外,调用者也可用将值回送给生成器(通过send()方法),以及要求生成器退出(close())。
  
  例子:



def counter(start_at=0):
count = start_at
while True:
val = (yield count)
if val is not None:
print("val is not None ", val)
count = val
else:
count += 1

c = counter(5)
print(c.next())    #5
print(c.next())    #6
print(c.next())    #7

c.send(100)
print(c.next())    #101

c.close()
c.next()           #StopIteration
  生成器带有一个初始化的值,每次调用生成器next()时对count累加1,用户可以send()重置这个值;而调用close()方法,会终结生成器。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-146118-1-1.html 上篇帖子: 获取上海地区AQI质量数据Python脚本 下篇帖子: Python 删除列表中的重复数据
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表