python迭代器常见用法实例分析


Posted in Python onNovember 22, 2019

本文实例讲述了python迭代器常见用法。分享给大家供大家参考,具体如下:

迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

1. 可迭代对象

我们已经知道可以对list、tuple、str等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。

但是,是否所有的数据类型都可以放到for…in…的语句中,然后让for…in…每次从中取出一条数据供我们使用,即供我们迭代吗?

>>> for i in 100:
...   print(i)
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
# int整型不是iterable,即int整型不是可以迭代的
# 我们自定义一个容器MyList用来存放数据,可以通过add方法向其中添加数据
>>> class MyList(object):
...   def __init__(self):
...       self.container = []
...   def add(self, item):
...       self.container.append(item)
...
>>> mylist = MyList()
>>> mylist.add(1)
>>> mylist.add(2)
>>> mylist.add(3)
>>> for num in mylist:
...   print(num)
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'MyList' object is not iterable
>>>
# MyList容器的对象也是不能迭代的

我们自定义了一个容器类型MyList,在将一个存放了多个数据的MyList对象放到for…in…的语句中,发现for…in…并不能从中依次取出一条数据返回给我们,也就说我们随便封装了一个可以存放多条数据的类型却并不能被迭代使用。

我们把可以通过for…in…这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable)**。

2. 如何判断一个对象是否可以迭代

可以使用 isinstance() 判断一个对象是否是 Iterable 对象:

In [50]: from collections import Iterable
In [51]: isinstance([], Iterable)
Out[51]: True
In [52]: isinstance({}, Iterable)
Out[52]: True
In [53]: isinstance('abc', Iterable)
Out[53]: True
In [54]: isinstance(mylist, Iterable)
Out[54]: False
In [55]: isinstance(100, Iterable)
Out[55]: False

3. 可迭代对象的本质

我们分析对可迭代对象进行迭代使用的过程,发现每迭代一次(即在for…in…中每循环一次)都会返回对象中的下一条数据,一直向后读取数据直到迭代了所有数据后结束。那么,在这个过程中就应该有一个“人”去记录每次访问到了第几条数据,以便每次迭代都可以返回下一条数据。我们把这个能帮助我们进行数据迭代的“人”称为迭代器(Iterator)。

可迭代对象的本质就是可以向我们提供一个这样的中间“人”即迭代器帮助我们对其进行迭代遍历使用。

可迭代对象通过__iter__方法向我们提供一个迭代器,我们在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据.

那么也就是说,一个具备了__iter__方法的对象,就是一个可迭代对象。

>>> class MyList(object):
...   def __init__(self):
...       self.container = []
...   def add(self, item):
...       self.container.append(item)
...   def __iter__(self):
...       """返回一个迭代器"""
...       # 我们暂时忽略如何构造一个迭代器对象
...       pass
...
>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True
>>>
# 这回测试发现添加了__iter__方法的mylist对象已经是一个可迭代对象了

4. iter()函数与next()函数

list、tuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。iter()函数实际上就是调用了可迭代对象的__iter__方法。

>>> li = [11, 22, 33, 44, 55]
>>> li_iter = iter(li)
>>> next(li_iter)
11
>>> next(li_iter)
22
>>> next(li_iter)
33
>>> next(li_iter)
44
>>> next(li_iter)
55
>>> next(li_iter)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration
>>>

注意,当我们已经迭代完最后一个数据之后,再次调用next()函数会抛出StopIteration的异常,来告诉我们所有数据都已迭代完成,不用再执行next()函数了。

5. 如何判断一个对象是否是迭代器

可以使用 isinstance() 判断一个对象是否是 Iterator 对象:

In [56]: from collections import Iterator
In [57]: isinstance([], Iterator)
Out[57]: False
In [58]: isinstance(iter([]), Iterator)
Out[58]: True
In [59]: isinstance(iter("abc"), Iterator)
Out[59]: True

6. 迭代器Iterator

通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。

一个实现了__iter__方法和__next__方法的对象,就是迭代器

class MyList(object):
  """自定义的一个可迭代对象"""
  def __init__(self):
    self.items = []
  def add(self, val):
    self.items.append(val)
  def __iter__(self):
    myiterator = MyIterator(self)
    return myiterator
class MyIterator(object):
  """自定义的供上面可迭代对象使用的一个迭代器"""
  def __init__(self, mylist):
    self.mylist = mylist
    # current用来记录当前访问到的位置
    self.current = 0
  def __next__(self):
    if self.current < len(self.mylist.items):
      item = self.mylist.items[self.current]
      self.current += 1
      return item
    else:
      raise StopIteration
  def __iter__(self):
    return self
if __name__ == '__main__':
  mylist = MyList()
  mylist.add(1)
  mylist.add(2)
  mylist.add(3)
  mylist.add(4)
  mylist.add(5)
  for num in mylist:
    print(num)

7. for…in…循环的本质

for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。

8. 迭代器的应用场景

我们发现迭代器最核心的功能就是可以通过next()函数的调用来返回下一个数据值。如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是说不用再将所有要迭代的数据都一次性缓存下来供后续依次读取,这样可以节省大量的存储(内存)空间。

举个例子,比如,数学中有个著名的斐波拉契数列(Fibonacci),数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

现在我们想要通过for…in…循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以用迭代器来实现,每次迭代都通过数学计算来生成下一个数。

class FibIterator(object):
  """斐波那契数列迭代器"""
  def __init__(self, n):
    """
    :param n: int, 指明生成数列的前n个数
    """
    self.n = n
    # current用来保存当前生成到数列中的第几个数了
    self.current = 0
    # num1用来保存前前一个数,初始值为数列中的第一个数0
    self.num1 = 0
    # num2用来保存前一个数,初始值为数列中的第二个数1
    self.num2 = 1
  def __next__(self):
    """被next()函数调用来获取下一个数"""
    if self.current < self.n:
      num = self.num1
      self.num1, self.num2 = self.num2, self.num1+self.num2
      self.current += 1
      return num
    else:
      raise StopIteration
  def __iter__(self):
    """迭代器的__iter__返回自身即可"""
    return self
if __name__ == '__main__':
  fib = FibIterator(10)
  for num in fib:
    print(num, end=" ")

9. 并不是只有for循环能接收可迭代对象

除了for循环能接收可迭代对象,list、tuple等也能接收。

li = list(FibIterator(15))
print(li)
tp = tuple(FibIterator(6))
print(tp)

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
在Python的列表中利用remove()方法删除元素的教程
May 21 Python
django批量导入xml数据
Oct 16 Python
python入门教程之识别验证码
Mar 04 Python
对python打乱数据集中X,y标签对的方法详解
Dec 14 Python
nohup后台启动Python脚本,log不刷新的解决方法
Jan 14 Python
python opencv实现证件照换底功能
Aug 19 Python
Python 元组操作总结
Sep 18 Python
利用python实现冒泡排序算法实例代码
Dec 01 Python
关于Pytorch的MLP模块实现方式
Jan 07 Python
解决c++调用python中文乱码问题
Jul 29 Python
Python 可视化神器Plotly详解
Dec 26 Python
Pyqt5将多个类组合在一个界面显示的完整示例
Sep 04 Python
python自动分箱,计算woe,iv的实例代码
Nov 22 #Python
python创建学生管理系统
Nov 22 #Python
Python如何计算语句执行时间
Nov 22 #Python
python生成器用法实例详解
Nov 22 #Python
关于pandas的离散化,面元划分详解
Nov 22 #Python
Python协程 yield与协程greenlet简单用法示例
Nov 22 #Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
Nov 22 #Python
You might like
虫族 ZERG 概述
2020/03/14 星际争霸
浅谈PHP正则表达式中修饰符/i, /is, /s, /isU
2014/10/21 PHP
php编程每天必学之表单验证
2016/03/01 PHP
php实现websocket实时消息推送
2018/03/30 PHP
Ucren Virtual Desktop V2.0
2006/11/07 Javascript
JS和jquery获取各种屏幕的宽度和高度的代码
2013/08/02 Javascript
jQuery常用知识点总结以及平时封装常用函数
2016/02/23 Javascript
Jquery基础之事件操作详解
2016/06/14 Javascript
Angularjs 实现动态添加控件功能
2017/05/25 Javascript
BootStrap table实现表格行拖拽效果
2018/12/01 Javascript
javascript面向对象三大特征之封装实例详解
2019/07/24 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
[03:48]显微镜下的DOTA2第四期——TP动作
2014/06/20 DOTA
Python中用startswith()函数判断字符串开头的教程
2015/04/07 Python
python获取多线程及子线程的返回值
2017/11/15 Python
python opencv之SURF算法示例
2018/02/24 Python
Python 批量合并多个txt文件的实例讲解
2018/05/08 Python
在mac下查找python包存放路径site-packages的实现方法
2018/11/06 Python
Python中利用LSTM模型进行时间序列预测分析的实现
2019/07/26 Python
Python 内置函数globals()和locals()对比详解
2019/12/23 Python
python matplotlib画盒图、子图解决坐标轴标签重叠的问题
2020/01/19 Python
Python常用base64 md5 aes des crc32加密解密方法汇总
2020/11/06 Python
CSS3 实现穿梭星空动画
2020/11/13 HTML / CSS
New Balance天猫官方旗舰店:始于1906年,百年慢跑品牌
2017/11/15 全球购物
为娇小女性量身打造:Petite Studio
2018/11/01 全球购物
New Balance加拿大官方网站:运动鞋和健身服装
2018/11/19 全球购物
Goodee官方商店:迷你投影仪
2021/03/15 全球购物
百度JavaScript笔试题
2015/01/15 面试题
怎样自定义一个异常类
2016/09/27 面试题
党员年终民主评议的自我评价
2013/11/05 职场文书
婚礼答谢宴主持词
2014/03/14 职场文书
《宿建德江》教学反思
2014/04/23 职场文书
初中生评语大全
2014/04/24 职场文书
八年级作文之感悟亲情
2019/11/20 职场文书
python字符串常规操作大全
2021/05/02 Python
pytorch 使用半精度模型部署的操作
2021/05/24 Python