python里面有很多的以__(注意:这里是两个下划线)开始和结尾的函数,利用它们可以完成很多复杂的逻辑代码,而且提高了代码的简洁性,下面以迭代器的概念引入相关内容。

迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。

迭代器是一个可以记住遍历的位置的对象。

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter() 和 next()。

字符串,列表或元组对象都可用于创建迭代器:

>>> list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

迭代器对象可以使用常规for语句进行遍历:

>>>list=[1,2,3,4]
>>>it = iter(list)    # 创建迭代器对象
>>>for x in it:
>>>    print (x, end=" ")
1 2 3 4

it = iter(list) 这一句可以不写,因为python内部会对for语句后面的对象进行如下的变换:

for x in iter(list)

创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。

iter() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。

next() 方法(Python 2 里是 next())会返回下一个迭代器对象。我们就可以通过next函数访问这个对象的下一个元素了,并且在你不想继续有迭代的情况下抛出一个StopIteration的异常(for语句会捕获这个异常,并且自动结束for)

创建一个返回数字的迭代器,初始值为 1,逐步递增 1:

class A(object):def __init__(self,end):self.start = 0self.end = enddef __iter__(self):return selfdef __next__(self):if self.start < self.end:self.start + = 1return self.startelse:raise StopIteration a = A(5)for i in a:print(i)

输出:

1
2
3
4
5

把for语句换成next函数也可以:

class A(object):def __init__(self,end):self.start = 0self.end = enddef __iter__(self):return selfdef __next__(self):if self.start < self.end:self.start + = 1return self.startelse:raise StopIteration a = A(5)print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a)) # 其实到这里已经完成了,我们在运行一次查看异常

输出:

0
1
2
3
4
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-51-d93a95b5b2c9> in <module>()21 print(next(a))22 print(next(a))
---> 23 print(next(a)) # 其实到这里已经完成了,我们在运行一次查看异常<ipython-input-51-d93a95b5b2c9> in __next__(self)13             return ret14         else:
---> 15             raise StopIteration16 17 a = MyRange(5)StopIteration:

可以看见一个很明显的好处是,每次产生的数据,是产生一个用一个,什么意思呢,比如我要遍历[0, 1, 2, 3…]一直到10亿,如果使用列表的方式,那么是会全部载入内存的,但是如果使用迭代器,可以看见,当用到了(也就是在调用了next)才会产生对应的数字,这样就可以节约内存了,这是一种懒惰的加载方式。

注:

(1)构造函数

构造函数也被称为构造器,当创建对象的时候第一个被自动调用的函数,系统默认提供了一个无参的构造函数 per = Person()

  • 语法:

    def  __ init__(self,arg1,arg2,...):函数体
    
  • 说明:

     当你没有在类中定义构造函数的话,系统默认提供了一个无参的构造函数arg1,arg2,...可以自己定义,但是,一般情况下,构造函数的形参列表和成员变量有关构造函数的特点:创建对象;给对象的成员变量赋值
    
  • 构造函数和成员函数之间的区别:

     成员函数的函数名可以自定义,但是,构造函数的函数名是固定的__init__成员函数需要被手动调用,但是,构造函数在创建对象的过程中是自动被调用的对于同一个对象而言,成员函数可以被调用多次,但是,构造函数只能被调用一次
    

(2)class、instance、object、method、function

class :类
instance:实例
object:对象,和instance等同
method:类中的方法
function:普通函数,类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self

——————
python里面的self,是谁啊?

(3)self:

self代表类的实例,而非类

class Test:def prt(self):print(self)print(self.__class__)t = Test()
t.prt()T = Test()
T.prt()

输出

​<__main__.Test object at 0x000001EDDE8BFFD0>
<class '__main__.Test'><__main__.Test object at 0x000001EDDE7C45F8>
<class '__main__.Test'>

从执行结果可以很明显的看出,self 指代引用类的method的实例,代表当前实例的地址,可以通过self.xxx来改变实例的属性
而 self.class 则指向类。

self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:

class Test:def prt(food):print(food)print(food.__class__)t = Test()
t.prt()T = Test()
T.prt()

输出:

<__main__.Test object at 0x000001EDDE7A69E8>
<class '__main__.Test'>
<__main__.Test object at 0x000001EDDE8BFFD0>
<class '__main__.Test'>

(4)Iterable、Iterator

Iterable: 有迭代能力的对象,一个类,实现了__iter__,那么就认为它有迭代能力,通常此函数必须返回一个实现了__next__的对象,如果自己实现了,你可以返回self,当然这个返回值不是必须的;
Iterator: 迭代器(当然也是Iterable),同时实现了 iter__和__next__的对象,缺少任何一个都不算是Iterator,比如下面例子中,A()可以是一个Iterable,但是A()和B()都不能算是和Iterator,因为A只实现了__iter(),而B只实现了__next__()。

class B(object):def __next__(self):raise StopIterationclass A(object):def __iter__(self):return B()a = A()
b = B()print(next(a))
print(next(b))

输出:

Traceback (most recent call last):File "d:/objectdetection/models/yolov3/Rebar_Detection-master/test.py", line 12, in <module>print(next(a))
TypeError: 'A' object is not an iteratorTraceback (most recent call last):File "d:/objectdetection/models/yolov3/Rebar_Detection-master/test.py", line 12, in <module>print(next(b))File "d:/objectdetection/models/yolov3/Rebar_Detection-master/test.py", line 3, in __next__raise StopIteration
StopIteration

我们可以使用collections里面的类型来进行验证:

class B(object):def __next__(self):raise StopIterationclass A(object):def __iter__(self):return B()from collections.abc import *a = A()
b = B()
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))print(isinstance(b, Iterable))
print(isinstance(b, Iterator))
True
False
False
False

可以对B类进行修改:

class B(object):def __next__(self):raise StopIterationdef __iter__(self):return Noneclass A(object):def __iter__(self):return B()from collections.abc import *a = A()
b = B()
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))print(isinstance(b, Iterable))
print(isinstance(b, Iterator))
True
False
True
True

(5)生成器

生成器是一个可以快速创建迭代器的工具

  • 简单的生成器:生成器表达式

我们可以用列表推导(生成式)来初始化一个列表:

list5 = [x for x in range(5)]
print(list5)   #output:[0, 1, 2, 3, 4]

我们用类似的方式来生成一个生成器,只不过我们这次将上面的[ ]换成( ):

gen = (x for x in range(5))
print(gen)
#output: <generator object <genexpr> at 0x0000000000AA20F8>

看到上面print(gen) 并不是直接输出结果,而是告诉我们这是一个生成器。那么我们要怎么调用这个gen呢。
有两种方式:

第一种:

for item in gen:print(item)
#output:
0
1
2
3
4

第二种:

print(next(gen))#output:0
print(next(gen))#output:1
print(next(gen))#output:2
print(next(gen))#output:3
print(next(gen))#output:4
print(next(gen))#output:Traceback (most recent call last):StopIteration

好了。现在可以考虑下背后的原理是什么了。
从第一个用for的调用方式我们可以知道生成器是可迭代的。更准确的说法是他就是个迭代器。
我们可以验证一下:

from collections import Iterable, Iterator
print(isinstance(gen, Iterable))#output:True
print(isinstance(gen, Iterator))#output:True

str,list,tuple,dict,set这些都是可迭代的,就是可用for来访问里面的每一个元素。但他们并不是迭代器。

  • 在 Python 中,使用了 yield 的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。


import sysdef fibonacci(n): # 生成器函数 - 斐波那契a, b, counter = 0, 1, 0while True:if (counter > n): returnyield aa, b = b, a + bcounter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成while True:try:print (next(f), end=" ")except StopIteration:sys.exit()from collections import Iterable, Iterator
print(isinstance(f, Iterable))#output:True
print(isinstance(f, Iterator))#output:True
#output
0 1 1 2 3 5 8 13 21 34 55
  • send和throw函数

注意上面说的yield表达式的返回值,我们以前使用的都是yield start这种格式,其实yield是有返回值的,默认情况下都是None,我们修改一下上面的MyRange

def MyRange(end):start = 0while start < end:x = yield start  # 这里增加了获取返回值print(x)  # 打印出来start += 1m = MyRange(5)
print(next(m))
print(next(m))
#输出
0
None
1

yield执行顺序上面已经说明了,这里打印了一个None,就是yield的返回值,那么说了这么多,就是为了说明send函数的参数,会作为yield的返回值的。

def MyRange(end):start = 0while start < end:x = yield startprint(x)start += 1m = MyRange(5)
print(next(m))
print(m.send(10))#输出
0
10
1

我们在来看看throw这个函数,它是让yield产生一个异常,接收三个参数,异常类型,异常值,trackback对象,其中后面两个可选,同send一样,会返回下一个值。

如果这个异常不在生成器函数里面进行处理,会抛出到调用者
def MyRange(end):start = 0while start < end:try:x = yield startexcept Exception as e:print(e)start += 1m = MyRange(5)
print(next(m))
print(m.throw(Exception, 'Some Exception'))
#输出
0
Some Exception
1

总结:
生成迭代器的方法有很多种。
1、同时实现了 __iter__和__next__的对象,缺少任何一个都不算是Iterator。
2、生成器是生成迭代器的工具。

————
【Python魔术方法】迭代器(iter__和__next)
Python3 迭代器与生成器
对Python生成器的理解

python—— __iter__和__next__相关推荐

  1. [转载] 【python魔术方法】迭代器(__iter__和__next__)

    参考链接: Python __iter __()和__next __()| 将对象转换为迭代器 文章目录 `__iter__` 和 `__next__`真正的迭代器总结 python里面有很多的以__ ...

  2. __getitem__、__iter__、__next__、iter和next的使用方法介绍

    文章目录 1. iter和next (1)iter() (2)next() 2. __getitem__方法 3. __iter__与__next__方法 4. for循环中,__next__方法比_ ...

  3. python中的__iter__ __reversed__ __next__

    __reversed__ 返回集合的倒叙迭代器,如果没有实现这个方法,reversed()会去使用__getitem__和__len__来实现 介绍__next__和 __iter__方法需要了解下可 ...

  4. __iter__ 和 __next__

    class F: def __init__(self,x): self.x = x def __iter__(self): #把对象 变成可迭代对象 return self def __next__( ...

  5. 编写一个生成器需要编写__iter__和__next__

      class _Iterator:""" 迭代器类 """def __init__(self,seq=None):self._bag_it ...

  6. 我的番茄工作法使用原则

    番茄工作法也用了一段时间了,好用的同时也带来了一些问题,比如不按时休息,到时间了不结束,什么事情都想"番茄"一下,达不到预定的目标和番茄数目很焦虑等.用番茄工作法,是为了提高效率, ...

  7. python : 自定义可迭代类,__iter__ ,__next__的作用

    在python3中,如果定义了一个类,类中有 __iter__(self),__next__(self)两个函数,则该类具有了迭代器的属性, 具体性质体现在: 如果该类的对象出现在一个for循环中,那 ...

  8. 完全理解Python迭代对象、迭代器、生成器

    本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators,俺写的这篇文章是按照自己的理解做的参考翻译,算不上是原文的中译版本,推荐阅读原文,谢谢网 ...

  9. 理解Python的迭代器(转)

    原文地址: http://python.jobbole.com/81916/ 另外一篇文章: http://www.cnblogs.com/kaituorensheng/p/3826911.html ...

最新文章

  1. WCF错误远程服务器返回了意外响应: (413) Request Entity Too Large。解决方案
  2. 12v电量显示制作方法_如何制作老式12v充电器(四款12v充电器设计制作详解)
  3. Promise-js异步加载解决方案
  4. mac 备份文件 太大 时间机器_新手必看!加速 Mac 时间机器备份速度教程,Time Machine 备份太慢的解决方法...
  5. drawio流程图软件_Win10 一般软件个人收集
  6. centos mysql-5.5.20_mysql-5.5.20+CentOS 6.2 编译安装全过程详解(2)
  7. linux下python3源码安装及卸载
  8. kotlin 复制对象属性_Kotlin面向对象编程笔记
  9. memcache 客户端性能对比试验
  10. Cannot change version of project facet Dynamic Web Module to 2.5解决方案
  11. php+mysql+apache的安装方法
  12. 泰勒公式的展开细节解析、本质、联想与思考
  13. 潮流计算机课设,(潮流计算的计算机算法课程设计范文.doc
  14. Spring集成Quartz定时器
  15. 有关《家》的经典歌曲_盘点《乐队的夏天》15首经典歌曲,太好听了!
  16. RTI DDS的xml说明
  17. 如何删除Mac下载PS后莫名其妙多出来的几个程序
  18. 服务器项目命名规则,云服务器命名规范
  19. 怎样用html设置文档格式,Dreamweaver使用CSS样式表设置网页文本格式
  20. 控制图简明原理及Plotly实现控制图Python实践

热门文章

  1. 如何防止被人拉进微信群?
  2. 项目迁移到OpenShift过程中遇到的问题总结
  3. 图像灰度变化(OpenCV)
  4. python 随机生成整数 浮点数 字符 排序 简单案例
  5. 技巧1:利用中国科技云通行证登录IEEE Xplore下载论文
  6. java多线程(详)
  7. 部分插件由于缺少依赖无法加载。要恢复这些插件提供的功能,需要修复这些问题并重启
  8. 王者荣耀角色注销后我的服务器列表怎么删除,如何注销已经玩过的王者荣耀创建的角色?...
  9. 雷军在“我看未来20年”上的演讲
  10. The name ‘save/Const:0‘ refers to a Tensor which does not exist