基础知识回顾:迭代器和生成器

迭代器

容器是用来储存元素的一种数据结构,将所有数据保存在内存中,在Python中典型的容器有:str,tuple,list,dict。大部分容器都是可迭代的,还有其他一些对象也可以迭代,例如文件对象及管道对象等。能被迭代的对象都称为可迭代对象(Iteratbles),可迭代对象除了被for循环调用,还有sum(),min(),max()等。迭代器对象是支持迭代器协议的对象,在Python中,支持迭代器协议就是能够实现对象的__iter__()和next()方法,其中__iter__()方法返回迭代器对象本身;next()方法返回迭代器对象的下一个元素,在结尾时引发StopIteration异常。

1.认识迭代器

 1 >>> x = [1,2,3]
 2 >>> y = iter(x)
 3 >>> y
 4 <listiterator object at 0x02FF39D0>
 5 >>> next(y)
 6 1
 7 >>> next(y)
 8 2
 9 >>> next(y)
10 3
11 >>> next(y)
12
13 Traceback (most recent call last):
14   File "<pyshell#33>", line 1, in <module>
15     next(y)
16 StopIteration
17 >>> type(x)
18 <type ‘list‘>
19 >>> type(y)
20 <type ‘listiterator‘>
21
22 >>> list1 = [1,2,3]
23 >>> for i in range(len(list1)):
24     print list1[i]
25
26
27 1
28 2
29 3
30 >>> for i in list1:
31     print i
32
33
34 1
35 2
36 3
37 >>> (i for i in list1)          #生成器表达式
38 <generator object <genexpr> at 0x030FEB70>
39 >>> [ i for i in list1]         #列表倒推式
40 [1, 2, 3]

2.自定义迭代器

 1 class MyRange(object):
 2       def __init__(self, n):
 3           self.idx = 0
 4           self.n = n
 5
 6       def __iter__(self):
 7           return self
 8
 9       def next(self):
10          if self.idx < self.n:
11              val = self.idx
12              self.idx += 1
13              return val
14          else:
15              raise StopIteration()
16
17 myRange = MyRange(3)
18
19 print myRange is iter(myRange)  #说明myRange既是一个可迭代对象,也是一个迭代器对象(迭代器的实例对象),迭代器对象 = iter(可迭代对象)
20 print [i for i in myRange]
21 print [i for i in myRange]

运行结果:

True
[0, 1, 2]
[]

像列表这种序列类型的对象,可迭代对象和迭代器对象是相互独立存在的,在迭代的过程中各个迭代器相互独立;但是,有的可迭代对象本身又是迭代器对象,那么迭代器就没法独立使用,改进后:

 1 #可迭代对象
 2 class MyRangeIterable:
 3     def __init__(self, n):
 4         self.n = n
 5
 6     def __iter__(self):
 7         return MyRangeItertor(self.n)
 8
 9 #迭代器对象
10 class MyRangeItertor(object):
11     def __init__(self, n):
12         self.idx = 0
13         self.n = n
14
15     def __iter__(self):
16         return self
17
18     def next(self):
19         if self.idx < self.n:
20             val = self.idx
21             self.idx += 1
22             return val
23         else:
24             raise StopIteration()
25
26 myRange = MyRangeIterable(3)
27 print myRange is iter(myRange)   #说明myRange只是一个可迭代对象
28 print [i for i in myRange]
29 print [i for i in myRange]

运行结果:

False
[0, 1, 2]
[0, 1, 2]

生成器

生成器其实就是一种特殊的迭代器。

语法上和函数类似:生成器函数和常规函数几乎是一样的。生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
自动实现迭代器协议:对于生成器可以调用它的iter和next方法,并且,在没有值可以返回的时候,生成器自动产StopIteration异常
状态挂起:生成器用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便下次在它离开的地方继续执行。

在Python中有两种类型的生成器:生成器函数以及生成器表达式。生成器函数就是包含yield参数的函数。生成器表达式与列表倒推式类似。

 1 #普通函数完成的求平方
 2 >>> def gensquares(N):
 3         res = []
 4         for i in range(N):
 5           res.append(i*i)
 6         return res
 7
 8 >>> for item in gensquares(5):
 9       print item
10
11 0 1 4 9 16
12
13 #生成器函数
14 >>> def gensquares(N):
15         for i in range(N):
16            yield i ** 2
17
18 >>> for item in gensquares(5):
19         print item
20
21 0 1 4 9 16
22
23 #列表倒推式
24 >>> squares = [x**2 for x in range(5)]
25 >>> squares
26 [0, 1, 4, 9, 16]
27
28 #生成器表达式
29 >>> squares = (x**2 for x in range(5))
30 >>> squares
31 <generator object at 0x00B2EC88>
32 >>> next(squares)
33 0
34 >>> next(squares)
35 1
36 >>> next(squares)
37 4
38 >>> list(squares)    #生成器只能遍历一次,所以只能输出余下的值
39 [9, 16]

总结:

1.迭代对象自动调用迭代协议,迭代对象除了被for循环调用,还有sum(),min(),max()等
2.生成器是一种特殊迭代器,且只能遍历一次
3.使用生成器的好处除了延迟计算,每次只返回一个值,节省内存外,还代码简洁可读性好。

时间: 2024-10-14 18:19:55

基础知识回顾:迭代器和生成器的相关文章

python基础知识7——迭代器,生成器,装饰器

迭代器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁.这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件 特点: 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

JS基础知识回顾:引用类型(一)

在ECMAScript中引用类型是一种数据结构,用于将数据和功能组织在一起,而对象时引用类型的一个实例. 尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构,所以虽然说引用类型与类看起来想死,但他们并不是相同的概念. 不过引用类型有的时候也可以被称为对象定义,因为他们描述的是一类对象所具有的属性和方法. 新对象是使用new操作符后跟一个构造函数来实现的,构造函数本身就是一个函数,只不过该函数时处于创建新对象的目的而定义的. ECMASc

java基础知识回顾之javaIO类--管道流PipedOutputStream和PipedIutputStream

管道流(线程通信流):管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream).管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上.如图所示: 1.管道输入流应该连接到管道输出流 ,输入流和输出流可以直接连接       2.使用多线程操作,结合线程进行操作.通常由某个线程从管道输入流中(PipedInputStream)对象读取.          并由其他线程将其写入到相应的端到输出流中.不能使用单线程

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

java基础知识回顾之---java String final类普通方法

辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /*     * 按照面向对象的思想对字符串进行功能分类.     *      *      * 1,获取:     * 1.1 获取字符串中字符的个数(长度).     *         int length();     * 1.2 取字符串中的某一个字符,其中的参数index指的是字符串中序数.字符串的序数从0开始到length()-1 .     *       

python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。

本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding:utf-8from com.wenhy.crawler_baidu_baike import url_manager, html_downloader, html_parser, html_outputer print "爬虫百度百科调度入口" # 创建爬虫类class SpiderMai

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字节的值,该如何在它上面调用方法? 二:值类型转换为引用类型--装箱 2.1CLR对值类型进行装箱时:新分配托管堆内存,将值类型的实例字段拷贝到新分配的内存中,返回托管堆中新分配对象的地址.这个地址就是一个指向对象的引用. int i = 10; Object obj = i; 三:将引用类型转换为值