迭代对象、迭代器、生成器浅析
来源:互联网 发布:安卓软件开发编程论坛 编辑:程序博客网 时间:2024/05/29 03:04
迭代对象、迭代器、生成器浅析
这三者都是迭代对象,可通过for循环逐个获取对象元素。生成器基本不占用内存无论有多大数据量,但是只能使用一次(也可以通过一些途径使用多次)。
迭代对象 iterables
能一次返回一个元素的对象,主要用于for
循环。
基本上python的所有容器(container)都是可迭代的,比如有序容器list, str, tuple,set 和无序容器dict, file,还有collections模块提供的几个亮瞎眼的容器namedtuple、OrderedDict、Counter、defaultdict、deque、ChainMap、UserDict、UserList、UserString。一般情况下,要扩展内置类型的功能需要通过子类化来实现,但轮子已被前辈造好,不仅性能好,而且使得代码更加简洁pythonic。
例子,Counter()用于统计元素出现的个数,是字典builtins.dict的子类。
通常做法:
s="afmldskmfl"occurrences = {}for _,e in enumerate(s): occurrences1[e]=occurrences1.get(e,0)+1#返回{';': 1, 'a': 3, 'd': 1, 'f': 1, 'k': 1, 'l': 1, 's': 3}
pothonic写法:
occurrences = Counter(s)#返回Counter({';': 1, 'a': 3, 'd': 1, 'f': 1, 'k': 1, 'l': 1, 's': 3})occurrences.most_common(2)#返回[('s', 3), ('a', 3)]
Counter()除了继承dict的方法,自己又实现了三个,elements()、most_common()、subtract()。
可迭代对象本质上是实现了魔法方法__iter__()
或__getitem__()
,该方法可以看做是所有迭代对象都要遵循的一个协议。所以,除了python内置的迭代对象,我们也可以在自己定义的class里通过重载__iter__()
来获得可迭代性。
大多容器是可迭代对象,只有少数是迭代器。比如list
就是个迭代对象,但如果调用了魔法方法__iter__()
,则会变成一个迭代器。例子如下。
x = [1,2,3]isinstance(x, clc.abc.Iterable)#返回Trueisinstance(x, clc.abc.Iterator)#返回Falsex1 = iter(x)#或者用x1 = x.__iter__()isinstance(x1, clc.abc.Iterator)#返回True
迭代器 iterator
迭代器必定是可迭代对象。
所以迭代器是可迭代对象的子类,必须遵循迭代协议,即有方法__iter__()
,同时自己也有方法__next__()
。
其实,__next__()
基本是实现了迭代对象的for循环操作,但区别是next
会耗尽迭代器,当到达元素末尾之后再调用next会出现StopIteration
异常,同时也是一次性的,耗尽之后再没法使用。
而for循环接收迭代对象的StopIteration
异常并以此为break条件,同时,for中使用迭代对象就完全可以工作了,没必要把迭代器放在for循环里,多此一举,而且最重要的是迭代对象不会耗尽。
一个迭代对象可通过魔法方法__iter__()
转变为一个迭代器,即iterator=iterable.__iter__()
或iterator=iter(iterable)
。
自己实现一个计算Fibonacci数列的迭代器:
import collections as clcclass Fibonacci(object): def __init__(self, n=10): self.a = 0 self.b = 1 self.n = n def __iter__(self): """若存在此方法,python解释器会把实例化的对象当做迭代对象""" return self def __next__(self): """若存在此方法,python解释器会把实例化的对象当做迭代器""" if self.n == 0: raise StopIteration self.a, self.b = self.b, self.a+self.b self.n -= 1 return self.bif __name__ == "__main__": z = Fibonacci(5)#实例化对象 print(isinstance(z, clc.abc.Iterable))#输出True print(isinstance(z, clc.abc.Iterator))#输出True print(next(z))#输出1 print(z.__next__())#输出2 for f in z: print(f)#输出3,5,8
虽然这不是实现Fibonacci数列很Pythonic的方式,但是可以了解迭代器的工作原理。
迭代器可以说是个鸡肋般的存在,远不如迭代对象用途广泛,近不如生成器那样高效简洁—-鲁迅。但他是生成器的基石。
生成器 generator
为什么叫生成器呢?其实是一种生成的迭代器(generate iterators),故也称generator iterators,简称generators,即生成器。
一个自定义生成器最显著的特征是yield
语句。当解释器看到存在yield
语句时,便知道这是个生成器定义。
普通函数用return
返回,而生成器用yield
作为名义上的返回。
当调用普通函数时,return
语句前的所有代码全部被执行,然后返回return
后的值;如果返回的是一个list
,则所有值都会写入这个list
存在于内存中。
当调用生成器时,每次调用会返回yield
后面的值并把当前位置记住,下次再调用时就从这个位置开始。所以,yield
语句可以写在一个无限循环里而不用提供终止函数的条件!因为每次返回一个值,所以基本不会占用内存,无论数据有多少。
其实,yield
实现的功能与__iter__()
+__next__()
是一样的。很显然,要实现同一个功能,定义一个类比直接用一个普通函数(plain function)更复杂。而yield
正好可以通过一个简单函数实现一个类才能干的事。
用生成器实现Fibonacci数列。
def fibonacci(n): a, b = 0, 1 while True: if n == 0: raise StopIteration yield b a, b = b, a+b n -= 1if __name__ == "__main__": z = fibonacci(5)#调用函数,将生成器赋给变量z print(isinstance(z, clc.abc.Iterable))#输出True print(isinstance(z, clc.abc.Iterator))#输出True print(next(z))#输出1 print(z.__next__())#输出2 for f in z: print(f)#输出3,5,8
python标准库里自带的生成器有range()
、dict.items()
、zip()
,map()
、open
等,功能都很强度,尤其是zip
对于一次性迭代多个迭代对象时更是效率惊人,可参照我的前一篇文章8行代码实现ui文件到py文件转换。
总结
从范围来讲,迭代对象>迭代器>生成器
网上的一张图片很清晰地解释了三者之间的关系。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(内容同步更新到微信公众号python数学物理,微信号python_math_physics)
- 迭代对象、迭代器、生成器浅析
- Python迭代对象、迭代器、生成器
- python迭代,可迭代对象,生成器,迭代器--
- 完全理解Python迭代对象、迭代器、生成器
- 完全理解Python迭代对象、迭代器、生成器
- 完全理解Python迭代对象、迭代器、生成器
- Python学习之迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解PYTHON迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- python迭代对象,迭代器,生成器,以及yield用法详解
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解python中的迭代器,迭代对象,生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- nginx upload模块+python 后端处理模仿fastdfs实现文件存取
- htk 工具使用介绍
- thrift服务化改造原理分析
- Unity序列化
- 解决pcb搭线问题的过程
- 迭代对象、迭代器、生成器浅析
- Ubuntu下安装Eclipse开发环境(Eclipse IDE for C/C++ Developers)
- eclipse开发go语言入门案例
- mongodb笔记05(MongoDB 复制(副本集))
- Ubuntu 14下apache2开启对.htaccess支持
- 第十三周项目3
- Day013
- “科林明伦杯”哈尔滨理工大学第七届程序设计团队赛 I.Aggie’s Tasks(带权的LIS)
- ObjectBox入门