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循环。

Python的迭代器与生成器的更多相关文章

  1. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  2. python之迭代器与生成器

    python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...

  3. Python之迭代器和生成器

    Python 迭代器和生成器 迭代器 Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string.list.tupl ...

  4. 【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  5. python的迭代器、生成器、装饰器

    迭代器.生成器.装饰器 在这个实验里我们学习迭代器.生成器.装饰器有关知识. 知识点 迭代器 生成器 生成器表达式 闭包 装饰器 实验步骤 1. 迭代器 Python 迭代器(Iterators)对象 ...

  6. Python之迭代器,生成器

    迭代器 1.什么是可迭代对象 字符串.列表.元组.字典.集合都可以被for循环,说明他们都是可迭代的. from collections import Iterable l = [1,2,3,4] t ...

  7. python之迭代器、生成器与面向过程编程

    目录 一 迭代器 二 生成器 三 面向过程编程 一.迭代器 1.迭代器的概念理解 ''' 迭代器从字面上理解就是迭代的工具.而迭代是每次的开始都是基于上一次的结果,不是周而复始的,而是不断发展的. ' ...

  8. day13 python学习 迭代器,生成器

    1.可迭代:当我们打印 print(dir([1,2]))   在出现的结果中可以看到包含 '__iter__', 这个方法,#次协议叫做可迭代协议 包含'__iter__'方法的函数就是可迭代函数 ...

  9. Python之迭代器及生成器

    一. 迭代器 1.1 什么是可迭代对象 字符串.列表.元组.字典.集合 都可以被for循环,说明他们都是可迭代的. 我们怎么来证明这一点呢? from collections import Itera ...

  10. python基础----迭代器、生成器、协程函数及应用(面向过程实例)

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

随机推荐

  1. Natas Wargame Level 19 Writeup(猜测令牌,会话劫持)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAq4AAAEKCAYAAADTmtdjAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF

  2. 响应式网站-全屏banner响应的2中方法 - 被吃掉的banner

    通常来讲, 设计师们喜欢把banner设计成全屏(1920px或以上) 主题内容控制在一定的范围内一般在1200px左右 这样的设计即可以在宽屏上的表现很好.也能向下兼容一些小屏幕的设备: 如下图(所 ...

  3. java虚拟机学习-JVM调优总结(5)

    数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对象本身, ...

  4. 读阿里巴巴Java开发手册v1.2.0之工程结构有感【架构篇】

    首先,把昨天那俩条sql语句的优化原因给大家补充一下,第一条效率极低,第二条优化后的,sql语句截图如下: 经过几个高手的评论和个人的分析: 第一条sql语句查询很慢是因为它首先使用了in关键字查询, ...

  5. Grid search in the tidyverse

    @drsimonj here to share a tidyverse method of grid search for optimizing a model's hyperparameters. ...

  6. rPithon vs. rPython(转)

    Similar to rPython, the rPithon package (http://rpithon.r-forge.r-project.org) allows users to execu ...

  7. 你为什么必须(从现在开始就)掌握linux

    写在前面 在我看来,人人都应该学习linux,但这不是本文探讨的重点.本文主要从软件测试人员的角度谈谈学习和掌握linux的重要性.必要性.紧迫性. 另外: 这里所说的linux系统,是unix系统和 ...

  8. javascript基础-闭包

    原理 函数里包含函数,即闭包. 包含函数的结果是,子函数会挟持父函数的活动对象.子函数在访问一个变量时,先读自身的活动对象,是否包含此变量,没有从父函数里找,还没有,去祖函数,层层回溯,直到windo ...

  9. oracle创建用户四部曲

    创建用户一般分四步: 第一步:创建临时表空间 第二步:创建数据表空间 第三步:创建用户并制定表空间 第四步:给用户授予权限 创建临时表空间 create temporary tablespace ho ...

  10. poj2069

    poj2069 题意 求一个覆盖所有点的最小球体的半径.即求空间内一点到所有点的距离的最大值最小的点. 分析 模拟退火算法,但这道题竟然不用随机函数就能过了,主要体现了算法的渐近收敛性, 起始点随意取 ...