详解python可迭代对象、迭代器和生成器
可迭代对象
什么是可迭代对象?顾名思义就是可以迭代的一个对象,再通俗点就是可以被for循环遍历的对象,如常用的list、str等数据类型。我们可以使用isinstance来判断这个数据是否是可迭代对象,在此要先从Iterable包中导入模块collections。
from collections import Iterable
a = 1 #int
b= [1,2,3] #list
c= "abc" #str
d = {1,2,3} #set
e = (1,2,3) #tuple
f = {1:'a',2:'b'}#dict
g = open('test.py')
print (isinstance(a,Iterable))
print (isinstance(b,Iterable))
print (isinstance(c,Iterable))
print (isinstance(d,Iterable))
print (isinstance(e,Iterable))
print (isinstance(f,Iterable))
print (isinstance(g,Iterable))
False
True
True
True
True
True
True
可以看出除了像int、float、complex这种基本类型外,其他的数据类型都是属于可迭代对象,包括文件对象。他们之所以被python内部认为是一种可迭代对象,是因为他们都具有__iter__方法,用hasattr可以看出来。
a = 1 #int
b= [1,2,3] #list
c= "abc" #str
d = {1,2,3} #set
e = (1,2,3) #tuple
f = {1:'a',2:'b'}#dict
g = open('test.py')
print (hasattr(a,'__iter__'))
print (hasattr(b,'__iter__'))
print (hasattr(c,'__iter__'))
print (hasattr(d,'__iter__'))
print (hasattr(e,'__iter__'))
print (hasattr(f,'__iter__'))
print (hasattr(g,'__iter__'))
False
True
True
True
True
True
True
靠__iter__这个方法我们就可以自己创造一个可迭代对象,如下所示:
from collections import Iterable
class A():
def __init__(self):
pass
def __iter__(self):
pass
class B():
def __init__(self):
pass
a = A()
b = B()
print (isinstance(a,Iterable))
print (isinstance(b,Iterable))
True
False
上面代码可以看出来,在一个类中加入了__iter__这个方法,实例化的对象就会被python内部认为是一个可迭代的对象。
迭代器
上面介绍了什么是可迭代对象。那么什么是迭代器呢?迭代器跟可迭代对象又是什么关系呢?那么先解释第一问,迭代器对象是要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的__iter__()和next()方法。其中__iter__()方法返回迭代器对象本身;next()方法返回容器的下一个元素,在结尾时引发StopIteration异常。事实上,我们可以用上述的方法来检测一下那些数据类型是不是属于迭代器。
from collections import Iterator
a = 1 #int
b= [1,2,3] #list
c= "abc" #str
d = {1,2,3} #set
e = (1,2,3) #tuple
f = {1:'a',2:'b'}#dict
g = open('test.py')
print (isinstance(a,Iterator))
print (isinstance(b,Iterator))
print (isinstance(c,Iterator))
print (isinstance(d,Iterator))
print (isinstance(e,Iterator))
print (isinstance(f,Iterator))
print (isinstance(g,Iterator))
False
False
False
False
False
False
True
结果显示除了文件对象,其他的数据类型都不是迭代器,上面说过,迭代器必须同时有__iter__和__next__方法,我们可以看看文件对象和列表,比较他们是否有__next__方法,依次验证。
print (hasattr(b,'__next__'))#list
print (hasattr(g,'__next__'))#文件对象
False
True
再讲一下可迭代对象和迭代器的区别,我们都知道在学习python时流行这么一句话“一切皆对象”,那么显然易见可迭代对象就包括了迭代器,之所以把把文件对象又叫做迭代器,是因为它多了一种__next__方法而已。
知道了上述所讲的内容后,我们就可以试着自己写一个迭代器,无非就是加入__iter__和__next__方法。
from collections import Iterator
class A():
def __init__(self,i):
self.n = 0
self.i = i
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
var = self.i
self.i -= 1
return var
else:
raise StopIteration()
a = A(5)
print (isinstance(a,Iterator))
for i in a:
print (i)
#True
#5
#4
#3
#2
#1
创建一个迭代器还可以使用python内置的函数iter和next,如下:
from collections import Iterator
a = [1,2,3]
b = iter(a)
print (next(b))
print (isinstance(b,Iterator))
1
True
上述代码用iter将一个可迭代对象变成了一个迭代器,然后就可以使用迭代器的专用方法next来一个一个地取出数据。
for循环内部机制
a = [1,2,3]
for i in a:
print(i)
#1
#2
#3
为什么一个列表放在for循环里就可以很快地取出内部所有元素呢?正常来说,一个可迭代对象是不能直接从其中取出元素的,但放在for循环里就可以,这是因为在循环时,它会先自动调用__iter__方法将列表变成一个迭代器,然后这个迭代器再调用其__next__()方法。
生成器
首先我们需要知道的是生成器本质就是一个迭代器,它同样拥有__iter__和__next__两个方法。与迭代器不同的是,他可以产生延迟操作,既不会立即出现结果,而是在你需要的时候才产生。生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果,在每个结果之间挂起和继续它们的状态,来自动实现迭代协议。也就是说,yield是一个语法糖,内部实现支持了迭代器协议,同时yield内部是一个状态机,维护着挂起和继续的状态。
def A(n):
print ("----生成器开始-----")
i = 1
while n != 0:
print("开始循环第%d次"%i)
yield n
n -= 1
print ("第%d循环结束"%i)
i += 1
print ("----生成器结束----")
a = A(3)
print (a.__next__())
----生成器开始-----
开始循环第1次
5
可以看出,生成器函数直接调用并不会马上执行,只有用next方法才能开始执行,next一次,他会直到碰到yield就会马上结束,当再次写一个next方法时(如下所示),它会在yield后继续执行下去,直到碰到下一个yield才会停止。如果没有找到yield,就会报出异常。
----生成器开始-----
开始循环第1次
5
第1循环结束
开始循环第2次
4
上述代码如果next方法执行四次,就会报出StopIteration错误。如下所示:
Traceback (most recent call last):
----生成器开始-----
开始循环第1次
File "D:/untitled/test.py", line 20, in <module>
3
第1循环结束
开始循环第2次
2
第2循环结束
开始循环第3次
1
print (a.__next__())
第3循环结束
----生成器结束----
StopIteration
生成器中还有两个很重要的方法:send()和close()。
send(value):next()方法可以恢复生成器状态并继续执行,其实send()是除next()外另一个恢复生成器的方法。与next不同的是,它需要传入一个参数,一般传入None,即send(None)与next()是等效的。
close():这个方法用于关闭生成器,对关闭的生成器后再次调用next或send将抛出StopIteration异常。
详解python可迭代对象、迭代器和生成器的更多相关文章
- python 可迭代对象 迭代器 生成器总结
可迭代对象 只要有魔法方法__iter__的就是可迭代对象 list和tuple和dict都是可迭代对象 迭代器 只要有魔法方法__iter__和__next__的就是可迭代对象 生成器 只要含有y ...
- python编程系列---可迭代对象,迭代器和生成器详解
一.三者在代码上的特征 1.有__iter__方法的对象就是可迭代类(对象) 2.有__iter__方法,__next()方法的对象就是迭代器3.生成器 == 函数+yield 生成器属于迭代器, 迭 ...
- 一文搞懂Python可迭代、迭代器和生成器的概念
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Python可迭代对象、迭代器和生成器
Python可迭代对象.迭代器和生成器 python 函数 表达式 序列 count utf-8 云栖征文 python可迭代对象 python迭代器 python生成器 摘要: 8.1 可迭代对象( ...
- 11.Python初窥门径(函数名,可迭代对象,迭代器)
Python(函数名,可迭代对象,迭代器) 一.默认参数的坑 # 比较特殊,正常来说临时空间执行结束后应该删除,但在这里不是. def func(a,l=[]): l.append(a) return ...
- Python中的可迭代对象/迭代器/For循环工作机制/生成器
本文分成6个部分: 1.iterable iterator区别 2.iterable的工作机制 3.iterator的工作机制 4.for循环的工作机制 5.generator的原理 6.总结 1.i ...
- Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器
Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器 一丶关键字:global,nonlocal global 声明全局变量: 1. 可以在局部作用域声明一 ...
- 孤荷凌寒自学python第十六天python的迭代对象
孤荷凌寒自学python第十六天python的迭代对象 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 迭代也就是循环. python中的迭代对象有相关的如下几个术语: A容器 contrai ...
- 详解Python编程中基本的数学计算使用
详解Python编程中基本的数学计算使用 在Python中,对数的规定比较简单,基本在小学数学水平即可理解. 那么,做为零基础学习这,也就从计算小学数学题目开始吧.因为从这里开始,数学的基础知识列位肯 ...
随机推荐
- Vue.js(20)之 封装字母表(是这个名字吗0.0)
HTML结构: <template> <div class="alphabet-container"> <h1>alphabet 组件</ ...
- [题解] CF622F The Sum of the k-th Powers
CF622F The Sum of the k-th Powers 题意:给\(n\)和\(k\),让你求\(\sum\limits_{i = 1} ^ n i^k \ mod \ 10^9 + 7\ ...
- (6)Mat对象的一些函数和方法的使用
首先是基本的代码整理 #include<iostream> #include<opencv.hpp> using namespace std; using namespace ...
- 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring IoC容器BeanFactory和ApplicationContext
IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建.Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring ...
- HttpServletRequest 的常用属性说明
HttpServletRequest 的常用属性总是被窝遗忘,人老了记性就不好.所以做个笔记,方便以后查看. 测试地址:http://127.0.0.1:8080/Test/test getConte ...
- Python csv文件操作
一.open文件打开和with open as 文件打开的区别 file= open("test.txt","r") try: for line in file ...
- 读书笔记 - javascript 高级程序设计 - 第一章 简介
第一章 简介 诞生时间 1995 最初用途 客服端验证 第一版标准 注意是标准 1997年 Ecma-262 一个完整的js实现由三部分组成 ECMAScript DOM 文档对象模型 BO ...
- 使用log4cxx
在java中有log4j日志模块,使用起来非常方便,在C++中也是有的,log4cxx就是log4j的c++移植版,机缘巧合之下今天想要使用一下这个日志模块,所以记录下自己从一开始下载安装到成功使用的 ...
- 北邮14&18年软院机试【参考】答案
2014 Problem A. 奇偶求和 题目描述: 给定N个数,分别求出这N个数中奇数的和以及偶数的和. 输入格式 第一行为测试数据的组数T(1<=T<=50).请注意,任意两组测试数据 ...
- 论 <解方程>
题面: 求n次整系数方程\(\sum_{i=1}^{n} a_ix^i = 0\)在区间\([1,m]\)上的整数解 解法: 1.暴力 O(NM) 暴力枚举+解方程 2.假设只要求一个解 瞎搞做法 引 ...