Python的迭代器与生成器-阿里云开发者社区

开发者社区> 科技小能手> 正文

Python的迭代器与生成器

简介:
+关注继续查看

迭代器

为了更好的理解迭代器和生成,我们需要简单的回顾一下迭代器协议的概念。

迭代器协议 

1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

for循环

for循环的本质:循环所有对象,全都是使用迭代器协议。

for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,

列表,字符串,元组,字典,集合,文件对象等本质上来说都不是可迭代对象,在使用for循环的时候内部是先调用他们内部的_iter_方法,使他们变成了可迭代对象,然后在使用可迭代对象的_next_方法依次循环元素,当元素循环完时,会触发StopIteration异常,for循环会捕捉到这种异常,终止迭代。

如访问一个list,可以使用平时习惯的写法:

#for循环访问#for循环l本质就是遵循迭代器协议的访问方式,先调用diedai_l=l.__iter__()方法,或者直接diedai_l=iter(l),然后依次执行diedai_l.next(),直到for循环捕捉到StopIteration终止循环li = [1,2,3,4]for i in li:#li_iter = li._iter_()
    print(i)#li_iter._next_

也可以直接使用迭代器访问:

复制代码

#迭代器协议访问li = [1,2,3,4]
f = li.__iter__()#第一步,先通过内部的_iter_方法,先把对象变成可迭代对象print(f.__next__())#对可迭代对象用_next_方法取值print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())#StopIteration,超出边界会报错

复制代码

生成器

在介绍生成器之前,先简单介绍一下列表生成式

列表生成式

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用range(1, 11):

>>> range(1, 11)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

列表生成式可以代替循环在编程中偷懒,如生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?可以用普通的循环,也可以用列表生成器完成,如下:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

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

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

创建生成器的两种方法

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

>>> L = [x * x for x in range(10)]>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range(10))>>> g<generator object <genexpr> at 0x104feab40>

L是一个list,而g是一个generator,如果想要访问生成器中元素,需要用生成器的next()方法。或者利用for循环,因为generator也是一个可迭代的对象。

第二种方法需要借助“yield”,以计算斐波那契数列为例,展示一个函数如何变成生成器,直接上代码:

def fib(max):
    n, a, b = 0, 0, 1    while n < max:        print b
        a, b = b, a + b
        n = n + 1

这是普通的函数,将print改为yield即为生成器:

def fib(max):
    n, a, b = 0, 0, 1    while n < max:        yield b
        a, b = b, a + b
        n = n + 1

函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。再举一个简单的例子,定义generator,返回1,3,5:

复制代码

>>> def odd():
...     print 'step 1'...     yield 1...     print 'step 2'...     yield 3...     print 'step 3'...     yield 5...>>> o = odd()>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>StopIteration

复制代码

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就报错。

同样,在获取元素时,大多数时候运用for循环。




本文转自lzwxx 51CTO博客,原文链接:http://blog.51cto.com/13064681/1943392

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
写一个通用的代码生成器
       代码生成器对于JAVA码农来说并不陌生。在一些业务性比较强,但编码比较规范的项目中,往往会有大量的重复或者类似的代码要写。比如对表的增删改查,比如生成用于远程调用的客户端方法存根等等。面对这种情况,程序员通常的做法就是拿一个现成模块的代码copy过来再改改。
2822 0
Charted – 自动化的可视化数据生成工具
  Charted 是一个让数据自动生成可视化图表的工具。只需要提供一个数据文件的链接,它就能返回一个美丽的,可共享的图表。Charted 不会存储任何数据。它只是获取和让链接提供的数据可视化。     在线演示      插件下载   您可能感兴趣的相关文章 网站开发中很有用...
749 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
7748 0
双 11 模块 79.34% 的代码是怎样智能生成的?
作为今年阿里经济体前端委员会的四大技术方向之一,前端智能化方向一被提及,就不免有人好奇:前端结合 AI 能做些什么,怎么做,未来会不会对前端产生很大的冲击等等。本篇文章将围绕这些问题,以「设计稿自动生成代码」场景为例,从背景分析、竞品分析、问题拆解、技术方案等几个角度切入,细述相关思考及过程实践。
9254 0
javascript中的迭代器
1.forEach迭代器 forEach方法接收一个函数作为参数,对数组中每个元素使用这个函数,只调用这个函数,数组本身没有任何变化 //forEach迭代器 function square(num){ document.
704 0
14426
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载