Python迭代器协议及for循环工作机制详解

一、递归与迭代

二、什么是迭代器协议

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

2、可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

3、协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

三、python中强大的for循环机制

for循环的本质:循环所有对象,全部是使用迭代器协议

解释:

有时会想,for循环的本质就是遵循迭代器协议访问对象,那么for循环的对象肯定都是迭代器了啊,没错,那既然这样,for循环可以遍历(字符串,,列表,字典,集合,文件对象),那这些类型的数据肯定都是可迭代对象啊?但是,为什么定义一个列表l=[1,2,3,4]没有next()方法。

(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环中,调用了他们内部的__iter__方法,把他们变成了可迭代对象

然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉stoplteration异常,已终止迭代

l=[1,2,3,4,5]
#下标访问方式
print(l[0])
print(l[7]) #超出访问会报IndexError: list index out of range

#遵循迭代器协议的方式
diedai=l.__iter__()
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__()) #超出边界会报StopIteration

#for循环访问方式:
#for循环本质就是遵循迭代器协议的访问方式,先调用diedai.__iter__()方法,或者直接diedai=iter(l),然后依次执行diedai.next(),直到for循环捕捉到StopIteration终止循环
#for循环所有对象的本质都是一样的道理

for i in l:     #diedai=l.__iter__()
  print(l[i])   #i=diedai.next()

#使用while模拟for循环做的事情
diedai_l=l.__iter__()
while True:
  try:
    print(diedai_l.__next__())
  except StopIteration:
    print("迭代完毕,终止循环")
    break

四、生成器初探

什么是生成器?

可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象

生成器分类及在python中的表现形式:(python有两种不同的方法提供生成器)

1、生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在没个结果中间,挂起函数的状态,以便下次用它离开的地方继续执行

2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

为何使用生成器以及生产器的优点:

python使用生成器对延迟操作提供了支持,所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果,这也是生产器的重要好处

import time
# def producer():
#   ret=[]
#   for i in range(100):
#     time.sleep(0.1)
#     ret.append('包子%s' %i)
#   return ret
#
# def consumer(res):
#   for index,baozi in enumerate(res):
#     time.sleep(0.1)
#     print('第%s个人,吃了%s' %(index,baozi))
#
# res=producer()
# consumer(res)

#yield 3相当于return 控制的是函数的返回值
#x=yield的另外一个特性,接受send传过来的值,赋值给x
# def test():
#   print('开始啦')
#   firt=yield #return 1  first=None
#   print('第一次',firt)
#   yield 2
#   print('第二次')
#
# t=test()
# res=t.__next__() #next(t)
# print(res)
# # t.__next__()
# # res=t.send(None)
# res=t.send('函数停留在first那个位置,我就是给first赋值的')
# print(res)

# def producer():
#   ret=[]
#   for i in range(100):
#     time.sleep(0.1)
#     ret.append('包子%s' %i)
#   return ret

def consumer(name):
  print('我是[%s],我准备开始吃包子了' %name)
  while True:
    baozi=yield
    time.sleep(1)
    print('%s 很开心的把【%s】吃掉了' %(name,baozi))

def producer():
  c1=consumer('wupeiqi')
  c2=consumer('yuanhao_SB')
  c1.__next__()
  c2.__next__()
  for i in range(10):
    time.sleep(1)
    c1.send('包子 %s' %i)
    c2.send('包子 %s' %i)
producer()

生产器小结

1、生成器是可迭代对象

2、实现了延迟计算、省内存

3、生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处

五、生成器表达式和列表解析

#1、三元表达式
name="alex"
name="yangyl"
res="1" if name=="yangyl" else "2"
print(res)

egg_list=["鸡蛋%s" %i for i in range(10) ]  #列表解析
print(egg_list)

#使用生产器获取
egg_two=("鸡蛋%s" %i for i in range(10))   #生产器表达式
print(egg_two)
print(egg_two.__next__())
print(next(egg_two))      #next()本质就是调用__next__

总结:

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

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

3、python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。列如:sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以我们可以直接这样计算一系列值的和:

s1=sum(x ** 2 for x in range(4))
print(s1)

而不用多此一举先构造一个列表

s2=sum([x ** 2 for x in range(4)])
print(s2)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 一篇文章弄懂Python中的可迭代对象、迭代器和生成器

    我们都知道,序列可以迭代.但是,你知道为什么吗? 本文来探讨一下迭代背后的原理. 序列可以迭代的原因:iter 函数.解释器需要迭代对象 x 时,会自动调用 iter(x).内置的 iter 函数有以下作用: (1) 检查对象是否实现了 iter 方法,如果实现了就调用它,获取一个迭代器. (2) 如果没有实现 iter 方法,但是实现了 getitem 方法,而且其参数是从零开始的索引,Python 会创建一个迭代器,尝试按顺序(从索引 0 开始)获取元素. (3) 如果前面两步都失败,Pyt

  • 浅谈Python中的生成器和迭代器

    迭代器 迭代器协议 对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么返回一个异常来终止本次迭代.(只能往前走,不能往后退!) 迭代器对象 遵循了(实现了)迭代器协议的对象.(对象内部实现了一个__next__方法,以实现迭代器协议)称为一个迭代器对象.他们的作用是逐个遍历容器中的对象.迭代器对象一定是可迭代对象 >>> from collections import Iterable, Iterator >>> l = list([1,2,3]) #

  • Python迭代器iterator生成器generator使用解析

    1. 迭代 根据记录的前面的元素的位置信息 去访问后续的元素的过程 -遍历 迭代 2. 可迭代对象 iterable 如何判断可迭代对象的3种方式 能够被迭代访问的对象 for in 常用可迭代对象-list tuple str from collections import Iterable isinstance(obj, Iterable) 3. 可迭代对象 可迭代对象通过__iter__方法提供一个 可以遍历对象中数据的工具-迭代器 iter(可迭代对象) 可以获取可迭代对象的迭代器 通过

  • Python生成一个迭代器的实操方法

    Python怎么生成一个迭代器,对于需要处理大型数据来说,迭代器是必不可少的,这样可节省大量内存空间,更加合理操作数据. 首先我们打开编辑器,这里以Sublime text3作为示范,创建一个新的py文档. rg = range(100) for i in rg: print(i) 我们知道range可以涵盖比较广的范围,但是如果数据太大的时候,一次性打印会占用比较多内存. rg = range(100) rg_iter = iter(rg) print(rg_iter) 那么这个时候我们就可以

  • Python进阶:生成器 懒人版本的迭代器详解

    从容器.可迭代对象谈起 所有的容器都是可迭代的(iterable),迭代器提供了一个next方法.iter()返回一个迭代器,通过next()函数可以实现遍历. def is_iterable(param): try: iter(param) return True except TypeError: return False params = [ 1234, '1234', [1, 2, 3, 4], set([1, 2, 3, 4]), {1:1, 2:2, 3:3, 4:4}, (1, 2

  • python 生成器和迭代器的原理解析

    一.生成器简介 在python中,生成器是根据某种算法边循环边计算的一种机制.主要就是用于操作大量数据的时候,一般我们会将操作的数据读入内存中处理,可以计算机的内存是比较宝贵的资源,我认为的当要处理的数据超过内存四分之一的大小时就应该使用生成器. 二.生成器有什么特点? 1.和传统的容器相比,生成器更节省内存. 2.延迟计算,在我们需要结果时就调用一下生成器的next()方法即可. 3.可迭代,你可以像遍历list一样,遍历生成器 三.如何创建生成器? 在python中有两种方式创建生成器:生成

  • 详解python中的生成器、迭代器、闭包、装饰器

    迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 1|1可迭代对象 以直接作用于 for 循环的数据类型有以下几种: 一类是集合数据类型,如 list . tuple . dict . set . str 等: 一类是 generator ,包括生成器和带 yield 的generator function. 这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable .

  • Python迭代器协议及for循环工作机制详解

    一.递归与迭代 二.什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个stopiteration异常,已终止迭代(只能往后走不能往前退) 2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法) 3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象. 三.python中强大的for循环机制 for循环的本质:循

  • python的内存管理和垃圾回收机制详解

    简单来说python的内存管理机制有三种 1)引用计数 2)垃圾回收 3)内存池 接下来我们来详细讲解这三种管理机制 1,引用计数: 引用计数是一种非常高效的内存管理手段,当一个pyhton对象被引用时其引用计数增加1,当其不再被引用时引用计数减1,当引用计数等于0的时候,对象就被删除了. 2,垃圾回收(这是一个很重要知识点): ①  引用计数 引用计数也是一种垃圾回收机制,而且是一种最直观,最简单的垃圾回收技术. 在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引

  • Session的工作机制详解和安全性问题(PHP实例讲解)

    我们先简单的了解一些http的知识,从而理解该协议的无状态特性.然后,学习一些关于cookie的基本操作.最后,我会一步步阐述如何使用一些简单,高效的方法来提高你的php应用程序的安全性以及稳定行. 我想大多数的php初级程序员一定会认为php默认的session机制的安全性似乎是有一定保障的,事实恰好相反 – php团队只是提供了一套便捷的session的解决方案提供给程序员使用,至于安全性的话,应该由程序员来加强,这是应用程序开发团队的责任.因为,这里面的方法很多,可以这么说吧,没有最好,只

  • 前端js中的事件循环eventloop机制详解

    前言 我们知道 js 是单线程执行的,那么异步的代码 js 是怎么处理的呢?例如下面的代码是如何进行输出的: console.log(1); setTimeout(function() { console.log(2); }, 0); new Promise(function(resolve) { console.log(3); resolve(Date.now()); }).then(function() { console.log(4); }); console.log(5); setTim

  • Javascript 引擎工作机制详解

    Javascript 引擎工作机制 javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等,这些概念正是JS引擎工作的核心组件.这篇文章的目的不是孤立的为你讲解每一个概念,而是通过一个简单的demo来展开分析,全局讲解JS引擎从定义到执行的每一个细节,以及这些概念在其中所扮演的角色. var x = 1; //定义一个全局变量 x function A

  • Python字典深浅拷贝与循环方式方法详解

    本节内容 深浅拷贝 循环方式 字典常用方法总结 一.深浅拷贝 列表.元组.字典(以及其他) 对于列表.元组和字典而言,进行赋值(=).浅拷贝(copy).深拷贝(deepcopy)而言,其内存地址是变化不通的. 赋值(=) 赋值只是创建一个变量,该变量指向原来的内存地址 >>> name1 = ['a','b',['m','n'],'c'] >>> name2 = name1 #输出结果,两个内存地址是一样的 >>> print(id(name1),'

  • Python中分支语句与循环语句实例详解

    前言 本篇博文介绍一下Python中的if条件语句.while循环语句.for in循环语句以及break和continue控制关键字. 分支的基本语法 if 条件表达式: 语句1 语句2 语句3 ...... 条件表达式就是计算结果必须为布尔值的表达式 表达式后面的冒号不能少 注意if后面的出现的语句,如果属于if语句块,则必须同一个锁紧等 if条件控制语句 条件控制语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块.if后面应该接一个条件,即一个布尔类型.而且Py

  • python列表删除和多重循环退出原理详解

    在学习python的时候,会有一些梗非常不适应,在此列举列表删除和多重循环退出的例子: 列表删除里面的坑 比如我们有一个列表里面有很多相同的值,假如:nums=[1,6,6,3,6,2,10,2,100],我想去掉6,可以这样写: nums=[1,6,6,3,6,2,10,2,100] for n in nums: if n==6: nums.remove(n) nums.sort() print(nums)#输出结果:[1, 2, 2, 3, 6, 10, 100] 排序显示后列表中还有一个6

  • Python中最快的循环姿势实例详解

    目录 各种姿势 比较快的姿势 最后 各种姿势 比如说有一个简单的任务,就是从 1 累加到 1 亿,我们至少可以有 7 种方法来实现,列举如下: 1.while 循环 def while_loop(n=100_000_000): i = 0 s = 0 while i < n: s += i i += 1 return s 2.for 循环 def for_loop(n=100_000_000): s = 0 for i in range(n): s += i return s 3.sum ran

  • javascript异步处理工作机制详解

    从基础的层面来讲,理解JavaScript的定时器是如何工作的是非常重要的.计时器的执行常常和我们的直观想象不同,那是因为JavaScript引擎是单线程的.我们先来认识一下下面三个函数是如何控制计时器的. var id = setTimeout(fn, delay); - 初始化一个计时器,然后在指定的时间间隔后执行.该函数返回一个唯一的标志ID(Number类型),我们可以使用它来取消计时器. var id = setInterval(fn, delay); - 和setTimeout有些类

随机推荐