一、【可迭代对象Iterable】

粗略判断的话,我们可以说能被for循环进行遍历的对象就是可迭代对象,如str,list,tuple,dict(key),set,range。

(open file 中的文件句柄属于迭代器的一种。)

如果想要更直观的判断的话,在这里我们使用dir()方法查看一下对象所有的可操作方法:

s ='hello,wutiele'
print(dir(s))
显示: ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

同样,dir列表,元祖,字典等类型的对象时也可以查看到有'iter'操作方法。

当然,上面的方法查看太麻烦,我们可以使用in的方法判断,返回布尔值为真的就是操作方法中有'iter'的,如:

l1 = ['lv1', 'lv2', 'lv3', 'lv4', 'lv5']
print('__iter__' in dir(l1)) 显示:
True 所以我们又可以说,内部含有'__iter__'方法的对象是可迭代对象。
可迭代对象遵循可迭代协议,可迭代协议的定义非常简单,就是内部实现了__iter__方法。
还有一种方法可以直观判断,那就是isinstance:
from collections import Iterable
t1 = ('枪兵', '射手', '剑士', '僧侣')
print(isinstance(t1, tuple))
print(isinstance(t1, Iterable)) 显示:
True
True isinstance同样作为判断类型的方法,它比type方法判断面更广,且返回的值是布尔值。

二、【迭代器Iterator】

迭代器英文是iterator。

迭代器比起可迭代对象来说,其实它只多包含了一个操作方法,那就是'__next__'方法。

下面使用__iter__将可迭代对象转化成迭代器,然后使用__next__方法操作一番,可以看到这个方法是做什么用的:
from collections import Iterable
t1 = ('枪兵', '射手', '剑士', '僧侣') t1_obj = t1.__iter__()
print(t1_obj)
print(type(t1_obj))
print(isinstance(t1_obj, Iterator))
print(isinstance(t1_obj, tuple)) 输出结果
<tuple_iterator object at 0x0000000000D90DA0>
<class 'tuple_iterator'>
True
False 可迭代对象转化成迭代器:可迭代对象.__iter__()
上例使用print和type查看从tuple转化的迭代器可以看到类型己经变成了tuple_iterator。 迭代器.__next__()
t1 = ('枪兵', '射手', '剑士', '僧侣')
t1_obj = t1.__iter__() print(t1_obj.__next__())
print(t1_obj.__next__())
print(t1_obj.__next__())
print(t1_obj.__next__()) # 返回
枪兵
射手
剑士
僧侣 如果再操作多一次.__next__会怎样?从头循环开始吗?答案是:
报错,StopIteration异常。 print(t1_obj.__next__())
StopIteration __next__方法每一次只会取出迭代器中的一个元素,是不是和for循环时的操作有点像?
其实for循环一个可迭代对像时,用到的就有__next__操作方法。 迭代器遵循迭代器协议:对象不仅含有__iter__方法,同时还含有__next__方法。 for循环,能遍历一个可迭代对象,他的内部到底进行了什么?
将可迭代对象转化成迭代器。(可迭代对象.__iter__())
内部使用__next__方法,一个一个取值。
加了异常处理功能,取值到底后自动停止。 【使用while模拟for循环机制】
li = [i for i in range(1, 100)]
# 转换成迭代器
l1_obj = li.__iter__()
while True:
# 异常处理,尝试进行try块区的语句,如果报错就执行except块区语句处理异常。
try:
j = l1_obj.__next__()
print(j)
# 当出现StopIteration异常时,不报错而是执行break中断while循环。
except StopIteration:
break

那么,使用for循环相比while,也就是迭代器它有什么好处呢?

首先没有迭代器的话,while只能处理有下标的列表,字符串和元祖,字典,集合,文件就不方便了;

其次,对大数据来说,使用迭代器比起直接使用列表(比如一百万个元素的列表),字符串(超大文本的日志)等节省内存空间多了,因为它的惰性机制,它生成后,只会在内存空间占用一条元素的空间;

满足惰性机制,取一个值才输出一个值;

同样由于怠惰,迭代器也不能反复取值(不能逆向或取到尽时重头又来),它内部有一个指针,取一个就指向到下一个,一直向前,不会反复。

迭代器最大的好处就是节省内存空间。

三、【生成器Generator】

生成器本质上也是迭代器(自带了__iter__方法和__next__方法),特点是惰性运算,开发者自定义。

目前知道的迭代器有两种:

一种是调用方法直接返回的;

一种是可迭代对象通过执行iter方法得到的。

迭代器的好处是可以节省内存。

如果在某些情况下,我们也需要节省内存,就只能自己写。自己写的这个能实现迭代器功能的东西就叫生成器。

生成器产生迭代器的方式:

1)生成器函数构造;

函数体中使用yield语句而不是return语句返回结果。

也就是说你只要在一个函数的函数体中看到有yield,你就知道它不是一个常规函数,而是一个生成器了。

yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行。

2)用生成器推导式构造;

3)数据类型的转化。

【生成器函数】

一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

【next】

例:next()取出生成器的值:

import time
def genrator_fun():
lv1 = '枪兵*14'
print('人族可以产出1级兵了!')
yield lv1
lv2 = '弓箭手*8'
print('人族可以产出2级兵了!')
yield lv2 g = genrator_fun()
print('g:', g) # 打印g输出生成器类型
print('-'*12, '我是华丽的分割线', '-'*12)
print(next(g)) # 使用next方法取出g生成器的第一个值(yield)
time.sleep(1)
print(next(g)) # 第二次执行取的是第二个值 g: <generator object genrator_fun at 0x0000000000DB86D0>
------------ 我是华丽的分割线 ------------
人族可以产出1级兵了!
枪兵*14
人族可以产出2级兵了!
弓箭手*8 例2:指针会顺着取出的值执行下去
def dead_sold():
# 可怕的亡灵大军,己经累积到1万个骷髅兵了!
for i in range(1, 10001):
yield '可怕的亡灵大军,己经累积到第 %s 个骷髅兵了!' % i
d = dead_sold() # 将函数赋值给一个变量,不然直接在下面的式子用会反复只取到第1个骷髅
for i in range(50):
print(d.__next__())
print('华丽分割线'.center(30, '-'))
for i in range(150):
print(d.__next__()) 可怕的亡灵大军,己经累积到第 47 个骷髅兵了!
可怕的亡灵大军,己经累积到第 48 个骷髅兵了!
可怕的亡灵大军,己经累积到第 49 个骷髅兵了!
可怕的亡灵大军,己经累积到第 50 个骷髅兵了!
------------华丽分割线-------------
可怕的亡灵大军,己经累积到第 51 个骷髅兵了!
可怕的亡灵大军,己经累积到第 52 个骷髅兵了!
可怕的亡灵大军,己经累积到第 53 个骷髅兵了!

上例中,取到第50个值时,再执行取值的语句时不会从第1个起执行,而是顺着51开始。

【send】

send和__next__()一样,都是执行下一个yield,不同的是,send还可以给上一个yield赋值。
当然,函数体中第一个取值语句不能为send,因为第一个之前并没有yield可给它进行赋值。
同样,最后一个yield不能接受send的赋值,因为最后一个后面并不能再取出值了。
send是取值和赋值同时进行的,且赋的是上一个yield的值。
def generator():
content = yield 1
print('=======', content, '=======') # 打印上一个yield的值
yield 2
yield 3 g = generator()
ret = g.__next__()
print('***', ret)
ret = g.send('hello') #send赋值给上一个yield
print('***', ret) *** 1
======= hello =======
*** 2

【列表推导式和生成器表达式】

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

例,创建1到10的列表:

l = [i for i in range(1,10)]

1.把列表解析的[]换成()得到的就是生成器表达式

2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存。

3.Python不但使用迭代器协议,让for循环变得更加通用。

大部分内置函数,也是使用迭代器协议访问对象的。

例如,sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:

sum(x ** 2 for x in range(1,11))

【补充】

1、可以直接作用于for循环的对象统称为可迭代对像;

2、可以被next()函数调用并不断返回下一个值的对象称为迭代器(iterator);

3、生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出stopIteration错误表示无法继续下一个值。

end

2018-4-4

铁乐学python_day13_迭代器生成器的更多相关文章

  1. 铁乐学python_Day43_协程

    铁乐学python_Day43_协程 引子 之前我们学习了线程.进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位. 按道理来说我们已经算是把cpu的利用率提高很多了. ...

  2. 铁乐学python_Day42_线程池

    铁乐学python_Day42_线程池 concurrent.futures 异步调用模块 concurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor: ...

  3. Learn day5 迭代器\生成器\高阶函数\推导式\内置函数\模块(math.time)

    1.迭代器 # ### 迭代器 """能被next调用,并不断返回下一个值的对象""" """ 特征:迭代器会 ...

  4. Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化

    本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...

  5. Python 迭代器&生成器

    1.内置参数     Built-in Functions     abs() dict() help() min() setattr() all() dir() hex() next() slice ...

  6. python杂记-4(迭代器&生成器)

    #!/usr/bin/env python# -*- coding: utf-8 -*-#1.迭代器&生成器#生成器#正确的方法是使用for循环,因为generator也是可迭代对象:g = ...

  7. Python学习笔记——基础篇【第四周】——迭代器&生成器、装饰器、递归、算法、正则表达式

    目录 1.迭代器&生成器 2.装饰器 a.基本装饰器 b.多参数装饰器 3.递归 4.算法基础:二分查找.二维数组转换 5.正则表达式 6.常用模块学习 #作业:计算器开发 a.实现加减成熟及 ...

  8. python 迭代器 生成器

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

  9. Python_迭代器-生成器-复习-习题_41

    # 迭代器和生成器# 迭代器 # 可迭代协议 —— 含有iter方法的都是可迭代的 # 迭代器协议 —— 含有next和iter的都是迭代器 # 特点 # 节省内存空间 # 方便逐个取值,一个迭代器只 ...

随机推荐

  1. C语言中的条件编译

    通常情况,我们想让程序选择性地执行,多会使用分支语句,比如if-else 或者switch-case 等.但有些时候,可能在程序的运行过程中,某个分支根本不会执行. 比如我们要写一个跨平台项目,要求项 ...

  2. Cookie文件说明及IE的Cookie文件格式

    1.Cookie文件的实质 Cookie实际上是Web服务端与客户端(典型的是浏览器)交互时彼此传递的一部分内容,内容可以是任意的,但要在允许的长度范围之内.客户端会将它保存在本地机器上(如IE便会保 ...

  3. unity简单动画实现

    1:创建一个Sprite Render (player)的动画对象并添加脚本Player,点击主菜单“Window(视窗)→Animation(动画窗口)”Animation面板(选中需要动画的对象) ...

  4. ant编译apache-nutch-2.2.1结合mysql实现爬虫的安装配置全过程

    之前的数据抓取都是用的八爪鱼软件,老大突发奇想要我自己搞个爬虫来抓取数据,网上找找貌似apache的nutch比较合适,于是就开始安装这啥nutch. 对于一个linux零基础的人来说,还要先学学li ...

  5. BG.VM--CentOS

    1. CentOS 更改IP 局域网配置: 在虚拟机的[网络]连接方式中选择:仅主机(Host-Only)网络. 路径:vim /etc/sysconfig/network-scripts/ifcfg ...

  6. BAT技术需求,你能达到多少?

    作为中国互联网界的传奇和标杆企业,BAT 三家公司的一举一动受互联网人的精密亲密关注.进入 BAT 成为大厂的一员成了许多互联网人职业生活生存追逐的方针之一. 本文的作者作为一个非科班毕业,出身于三流 ...

  7. hdu2036(多边形面积)

    Description “ 改革春风吹满地, 不会AC没关系; 实在不行回老家, 还有一亩三分地. 谢谢!(乐队奏乐)” 话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而 ...

  8. java设计模式-----18、职责链模式

    概念: Chain of Responsibility(CoR)模式也叫职责链模式.责任链模式或者职责连锁模式,是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的 ...

  9. 小tip: base64:URL背景图片与web页面性能优化——张鑫旭

    一.base64百科 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息. 某人: 唉,我彻底废柴了,为何上面明明是中文,洒家却看不懂嘞,为什 ...

  10. BZOJ3832: [Poi2014]Rally(拓扑排序 堆)

    题意 题目链接 Sol 最直观的思路是求出删除每个点后的最长路,我们考虑这玩意儿怎么求 设\(f[i]\)表示以\(i\)结尾的最长路长度,\(g[i]\)表示以\(i\)开始的最长路长度 根据DAG ...