网站建设出找不到网页,遵义城乡住房建设厅网站,营销推广是什么意思,网站开发 只要参考链接#xff1a; Python __iter __()和__next __()| 将对象转换为迭代器
文章目录 __iter__ 和 __next__真正的迭代器总结 python里面有很多的以__开始和结尾的函数#xff0c;利用它们可以完成很多复杂的逻辑代码#xff0c;而且提高了代码的简洁性#xff0c;本文主…参考链接 Python __iter __()和__next __()| 将对象转换为迭代器
文章目录 __iter__ 和 __next__真正的迭代器总结 python里面有很多的以__开始和结尾的函数利用它们可以完成很多复杂的逻辑代码而且提高了代码的简洁性本文主要总结了迭代器用到的魔术方法并且主要以代码例子进行解释。
__iter__ 和 __next__
其实这里需要引入一个概念叫迭代器常见的就是我们在使用for语句的时候python内部其实是把for后面的对象上使用了内建函数iter比如
a [1, 2, 3]
for i in a: do_something() 其实在python内部进行了类似如下的转换
a [1, 2, 3]
for i in iter(a): do_something() 那么iter返回的是什么呢就是一个迭代对象它主要映射到了类里面的__iter__函数此函数返回的是一个实现了__next__的对象。注意理解这句话比如
class B(object): def __next__(self): raise StopIteration class A(object): def __iter__(self): return B() 我们可以看见A这个类实现了一个__iter__函数返回的是B()的实例对象其中B里面实现了__next__这个函数。
下面引入几个概念 Iterable: 有迭代能力的对象一个类实现了__iter__那么就认为它有迭代能力通常此函数必须返回一个实现了__next__的对象如果自己实现了你可以返回self当然这个返回值不是必须的 Iterator: 迭代器(当然也是Iterable)同时实现了__iter__和__next__的对象缺少任何一个都不算是Iterator比如上面例子中A()可以是一个Iterable但是A()和B()都不能算是和Iterator因为A只实现了__iter__而B只实现了__next__()。
我们可以使用collections里面的类型来进行验证
class B(object): def __next__(self): raise StopIteration class 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 StopIteration def __iter__(self): return None class 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 真正的迭代器
上面只是做了几个演示这里具体说明一下: 当调用iter函数的时候生成了一个迭代对象要求__iter__必须返回一个实现了__next__的对象我们就可以通过next函数访问这个对象的下一个元素了并且在你不想继续有迭代的情况下抛出一个StopIteration的异常(for语句会捕获这个异常并且自动结束for)下面实现了一个自己的类似range函数的功能。
class MyRange(object): def __init__(self, end): self.start 0 self.end end def __iter__(self): return self def __next__(self): if self.start self.end: ret self.start self.start 1 return ret else: raise StopIteration from collections.abc import * a MyRange(5)
print(isinstance(a, Iterable))
print(isinstance(a, Iterator)) for i in a: print(i) 结果是
True
True
0
1
2
3
4 接下来我们使用next函数模拟一次
class MyRange(object): def __init__(self, end): self.start 0 self.end end def __iter__(self): return self def __next__(self): if self.start self.end: ret self.start self.start 1 return ret else: raise StopIteration a MyRange(5)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a)) # 其实到这里已经完成了我们在运行一次查看异常 可以看见一个很明显的好处是每次产生的数据是产生一个用一个什么意思呢比如我要遍历[0, 1, 2, 3.....]一直到10亿如果使用列表的方式那么是会全部载入内存的但是如果使用迭代器可以看见当用到了(也就是在调用了next)才会产生对应的数字这样就可以节约内存了这是一种懒惰的加载方式。
总结
可以使用collection.abs里面的Iterator和Iterable配合isinstance函数来判断一个对象是否是可迭代的是否是迭代器对象iter实际是映射到了__iter__函数只要实现了__iter__的对象就是可迭代对象(Iterable)正常情况下应该返回一个实现了__next__的对象(虽然这个要求不强制)如果自己实现了__next__当然也可以返回自己同时实现了__iter__和__next__的是迭代器(Iterator)当然也是一个可迭代对象了其中__next__应该在迭代完成后抛出一个StopIteration异常for语句会自动处理这个StopIteration异常以便结束for循环
生成器相关的文档已经在这里。