SECTION 19 函数和函数式编程(六)
创始人
2024-04-23 20:42:15
0

函数和函数式编程

    • 19.1 迭代器
        • 19.1.1 创建一个迭代器
        • 19.1.2 其他生成迭代器的方式
        • 19.1.3 可迭代的对象
        • 19.1.4 迭代器示例
    • 19.2 生成器
        • 19.2.1 生成器的“动机”
        • 19.2.2 什么是 python 式的生成器?
        • 19.2.3 简单的生成器特性
        • 19.2.4 在哪使用生成器?
        • 19.2.5 加强的生成器特性

注:本章为“SECTION 9 迭代器”扩展

19.1 迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器

举个例子说明:
比如说我们去超市买水果,而正巧超市的服务人员正在摆放苹果。服务人员告诉我们需要等苹果都摆放完毕我们才可以拿苹果,这样就很耽误我们的时间。(这个场景中,柜台上其实已经有苹果了,只不过销售不让拿罢了。)
然后我们再去卖橘子的柜台,服务人员也在摆放橘子。但是服务人员告诉我们可以不用等他摆放完毕,我们可以直接拿橘子,这样就会很好的节省我们的时间。如果我们拿橘子的速度超过了服务人员摆放的速度 ,我们只需要等待服务人员摆放之后就可以直接拿橘子,大大的提升了我们买橘子的效率。

而迭代器就类似于我们买橘子的场景,我们平时的程序都是一次性写入到内存中。比如我们的列表中存在成百上千的数据,都是一次性写入到内存里的,通过这样让我们来使用。但是迭代器却是按需加载,有一点内容就会放在内容里面,我们就可以立刻使用内存中的数据进行我们的逻辑处理。这样就不要所有的数据都写入到内存中就可以使用,大大的提升了使用效率。

19.1.1 创建一个迭代器

iter()函数介绍:生成一个迭代器对象
iter()函数用法:iter(iterable)
iter(iterable)从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象

next(iterable) 从迭代器iterator中获取下一了记录,如果无法获取下一条记录,则触发stoptrerator异常

迭代器示例

#coding:utf-8
from time import  sleep
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
print (next(it))   # 输出迭代器的下一个元素
print (next(it))
print (next(it))
print (next(it))
print
sleep(1)
print (next(it))
1
2
3
4Traceback (most recent call last):File "C:/Users/Administrator/Desktop/test.py", line 11, in print (next(it))
StopIteration

19.1.2 其他生成迭代器的方式

除了刚刚我们使用的 iter() 函数之外 ,我们还有其他方法生成迭代器:

第一种:for循环生成方法 ,我们可以在函数中使用 for 循环, 并对每一个 for 循环的成员使用 yield() 函数 [它的意思就是将每一个 for 循环成员放到一个迭代器对象中,不过只有被调用才会被放入。]

def test():for i in range(3):yield iresult = test()print 'for ,no.1 i =', next(result)
print 'for ,no.2 i =', next(result)
print 'for ,no.3 i =', next(result)
print 'for ,no.4 i =', next(result)
for ,no.1 i = 0
for ,no.2 i = 1
for ,no.3 i = 2
for ,no.4 i =
Traceback (most recent call last):File "C:/Users/Administrator/Desktop/test.py", line 11, in print 'for ,no.4 i =', next(result)
StopIteration

第二种:for 循环一行生成迭代器对象

result = (i for i in [1, 2, 3])print 'for ,no.1 i =', next(result)
print 'for ,no.2 i =', next(result)
print 'for ,no.3 i =', next(result)
print 'for ,no.4 i =', next(result)
for ,no.1 i = 1
for ,no.2 i = 2
for ,no.3 i = 3
for ,no.4 i =
Traceback (most recent call last):File "C:/Users/Administrator/Desktop/test.py", line 8, in print 'for ,no.4 i =', next(result)
StopIteration

注意:使用 for 循环生成的迭代器,可以不使用 next() 函数 也可以执行,(依然可以通过 for 循环 获取迭代器的数据)不仅如此,当我们调取完迭代器中的数据之后,程序不会抛出异常,相比较与 next() 函数要友好的多。—生成器

19.1.3 可迭代的对象

类似于list、tuple、str 等类型的数据可以使用for… in… 的循环遍历语法可以从其中依次拿到数据并进行使用,我们把这个过程称为遍历,也称迭代。python中可迭代的对象有list(列表)、tuple(元组)、dirt(字典)、str(字符串)set(集合)等。

19.1.4 迭代器示例

迭代器对象可以使用常规for语句进行遍历

list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:print x,
print
1 2 3 4

也可以使用 next() 函数

import sys         # 引入 sys 模块list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象while True:try:print (next(it))except StopIteration:sys.exit()

19.2 生成器

19.2.1 生成器的“动机”

我们讨论了迭代器背后的有效性以及它们如何给非序列对象一个像序列的迭代器接口。这很容易明白因为他们仅仅只有一个方法,用于调用获得下个元素的 next()。然而,除非你实现了一个迭代器的类,迭代器真正的并没有那么“聪明“。难道调用函数还没有强大到在迭代中以某种方式生成下一个值并且返回和 next()调用一样简单的东西?那就是生成器的动机之一。

生成器的另外一个方面甚至更加强力…协同程序的概念。协同程序是可以运行的独立函数调用,可以暂停或者挂起,并从程序离开的地方继续或者重新开始。在有调用者和(被调用的)协同程序也有通信。举例来说,当协同程序暂停的时候,我们能从其中获得一个中间的返回值,当调用
回到程序中时,能够传入额外或者改变了的参数,但仍能够从我们上次离开的地方继续,并且所有状态完整。挂起返回出中间值并多次继续的协同程序被称为生成器,那就是 python 的生成器真正在做的事。

在 2.2 的时候,生成器被加入到 python 中接着在 2.3 中成为标准(见 PEP255),虽然之前足够强大,但是在 Python2.5 的时候,得到了显著的提高(见 pep342)。这些提升让生成器更加接近一个完全的协同程序,因为允许值(和异常)能传回到一个继续的函数中。同样地,当等待一个生成器的时候,生成器现在能返回控制。在调用的生成器能挂起(返回一个结果)之前,调用生成器返回一个结果而不是阻塞等待那个结果返回。让我们更进一步观察生成器自顶向下的启动.

19.2.2 什么是 python 式的生成器?

从句法上讲,生成器是一个带 yield 语句的函数。一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果----那就是 yield 语句的功能, 返回一个值给调用者并暂停执行。当生成器的 next()方法被调用的时候,它会准确地从离开地方继续(当它返回[一个值以及]控制给调用者时)当在 2.2 生成器被加入的时候,因为它引入了一个新的关键字yield,为了向下兼容,你需要从_future_模块中导入 generators 来使用生成器。从 2.3 开始,当生成器成为标准的时候,这就不再是必需的了。

19.2.3 简单的生成器特性

与迭代器相似,生成器以另外的方式来运作:当到达一个真正的返回或者函数结束没有更多的值返回(当调用 next()),一个 StopIteration 异常就会抛出。这里有个例子,简单的生成器:

def simpleGen():
yield 1
yield '2 --> punch!'

现在我们有自己的生成器函数,让我们调用他来获得和保存一个生成器对象(以便我们能调用它的 next()方法从这个对象中获得连续的中间值)

>>> myG = simpleGen()
>>> myG.next()
1
>>> myG.next()
'2 --> punch!'
>>> myG.next()
Traceback (most recent call last):
File "", line 1, in ?
myG.next() StopIteration

由于 python 的 for 循环有 next()调用和对 StopIteration 的处理,使用一个 for 循环而不是手动迭代穿过一个生成器(或者那种事物的迭代器)总是要简洁漂亮得多。

>>> for eachItem in simpleGen():
... print eachItem
...
1
'2 --> punch!'

当然这是个挺傻的例子:为什么不对这使用真正的迭代器呢?许多动机源自能够迭代穿越序列,而这需要函数威力而不是已经在某个序列中静态对象。在接下来的例子中,我们将要创建一个带序列并从那个序列中返回一个随机元素的随机迭代器:

from random import randint
def randGen(aList):while len(aList) > 0:yield aList.pop(randint(0, len(aList)))

不同点在于每个返回的元素将从那个队列中消失,像一个 list.pop()和 random.choice()的结合的归类。

>>> for item in randGen(['rock', 'paper', 'scissors']):
... print item
...
scissors
rock
paper

19.2.4 在哪使用生成器?

在接下来的几章中,当我们谈到面向对象编程的时候,将看见这个生成器较简单(和无限)的版本作为类的迭代器。在几章前的小节中,我们讨论了生成器表达式的语法。使用这个语法返回的对象是个生成器,但只以一个简单的形式,并允许使用过分简单化的列表解析的语法。这些简单的例子应该让你有点明白生成器是如何工作的,但你或许会问。"在我的应用中,我可以在哪使用生成器?“或许,你会问“最适合使用这些个强大的构建的地方在哪?“

使用生成器最好的地方就是当你正迭代穿越一个巨大的数据集合,而重复迭代这个数据集合是一个很麻烦的事,比如一个巨大的磁盘文件,或者一个复杂的数据库查询。对于每行的数据,你希望执行非元素的操作以及处理,但当正指向和迭代过它的时候,你“不想失去你的地盘“。你想要抓取一块数据,比如,将它返回给调用者来处理以及可能的对(另外一个)数据库的插入,接着你想要运行一次 next()来获得下一块的数据,等等。

状态在挂起和再继续的过程中是保留了的,所以你会觉得很舒服有一个安全的处理数据的环境。没有生成器的话,你的程序代码很有可能会有很长的函数,里面有一个很长的循环。当然,这仅仅是因为一个语言这样的特征不意味着你需要用它。如果在你程序里没有明显适合的话,那就别增加多余的复杂性!当你遇到合适的情况时,你便会知道什么时候生成器正是要使用的东西。

19.2.5 加强的生成器特性

在 python2.5 中,一些加强特性加入到生成器中,所以除了 next()来获得下个生成的值,用户可以将值回送给生成器[send()],在生成器中抛出异常,以及要求生成器退出[close()]。由于双向的动作涉及到叫做 send()的代码来向生成器发送值(以及生成器返回的值发送回来),现在 yield 语句必须是一个表达式,因为当回到生成器中继续执行的时候,你或许正在接收一个进入的对象。

我们用简单的闭包例子,counter:

>>> def counter(start_at=0):
...     count=start_at
...     while True:
...             val=(yield count)
...             if val is not None:
...                     count=val
...             else:
...                     count+=1
... 
>>> count=counter(5)
5
>>> count.next()
6
>>> count.send(9)
9
>>> count.next()
10
>>> count.close()
>>> count.next()
Traceback (most recent call last):File "", line 1, in 
StopIteration

相关内容

热门资讯

自动打开应用安卓系统,安卓系统... 你有没有想过,手机里的那些应用,有时候真是让人又爱又恨呢?有时候,我们急需某个应用,却得费老大力气去...
安卓系统防沉迷软件,守护青少年... 你有没有发现,现在手机上玩游戏的诱惑力简直让人无法抗拒?尤其是安卓系统,那丰富的游戏资源,简直让人停...
流量最快的安卓系统,揭秘流量最... 你有没有想过,为什么你的手机总是那么卡,而别人的手机却像开了挂一样流畅?是不是好奇,为什么有些安卓系...
小米5换换安卓系统,畅享极致性... 你有没有想过,你的小米5手机,那个陪伴你走过无数日夜的小家伙,是不是也该给它来个“换新装”了呢?没错...
国产的安卓系统手机,畅享智能生... 你有没有发现,最近国产的安卓系统手机越来越火了?没错,就是那种咱们自己研发的系统,那种让外国品牌都不...
安卓系统刷入停止,探究原因与解... 你有没有遇到过这种情况?手机刷机过程中突然停止了,安卓系统刷入停滞不前,心里那个急啊!别慌,今天就来...
汽车是安卓系统嘛,安卓系统在智... 你有没有想过,汽车里那个神奇的操作系统,是不是和安卓手机里的一样呢?没错,今天咱们就来聊聊这个话题—...
网易狼人杀 安卓系统,体验指尖... 亲爱的玩家们,你是否曾在深夜里,手机屏幕前,与一群好友展开一场惊心动魄的“狼人杀”对决?今天,就让我...
小米安卓系统小主机,探索小米安... 你有没有想过,家里的电视、电脑、平板,甚至手机,其实都可以变成一个超级智能的娱乐中心?没错,这就是小...
卡刷安卓系统大全,全面解析各类... 你有没有想过,你的安卓手机可以像变形金刚一样,随心所欲地变换模样?没错,今天就要给你揭秘一个神奇的世...
安卓系统测试流畅度,安卓系统流... 你有没有发现,现在手机更新换代的速度简直就像坐上了火箭呢!尤其是安卓系统,每次更新都让人眼前一亮。但...
安卓系统50怎么升级,轻松迈向... 亲爱的安卓用户们,你是否也像我一样,对安卓系统的更新充满了期待?没错,就是那个让我们的手机焕然一新的...
安卓5.1.1操作系统,系统特... 你知道吗?在手机世界里,操作系统就像是个大管家,它不仅决定了手机的脸面,还掌管着手机的所有“家务事”...
手机安卓系统如果升级,体验流畅... 亲爱的手机控们,你们有没有发现,你的安卓手机最近是不是总在提醒你更新系统呢?别急,别急,今天就来给你...
安卓系统怎么禁止待机,安卓系统... 手机待机时间短,是不是让你头疼不已?别急,今天就来教你一招,让你的安卓手机告别“短命”模式,延长待机...
亿联安卓苹果系统,跨平台沟通新... 你知道吗?在科技飞速发展的今天,手机操作系统可是咱们日常生活中不可或缺的一部分。说起手机系统,亿联安...
smoothx安卓系统安装ap... 你有没有想过,为什么你的手机里总是乱糟糟的,各种app堆在一起,找起来费劲得很?别急,今天就来教你怎...
安卓系统图库在哪里,图库应用位... 你有没有发现,手机里的照片越来越多,有时候想找一张特定的照片,却像大海捞针一样困难?别急,今天就来告...
安卓7.0系统自带彩蛋,隐藏彩... 你知道吗?安卓7.0系统里竟然藏着不少小秘密,就像一颗颗隐藏的彩蛋,等着我们去发现。今天,就让我带你...
安卓系统好用的电池,好用到飞起... 你有没有发现,用安卓手机的时候,电池续航能力简直让人爱不释手啊!没错,今天咱们就来聊聊这个话题——安...