可迭代对象与迭代器
from collections import Iterable
from collections import Iterator
"""
手工迭代
"""
# aIt是一个可迭代对象
aIt = [1,2,3,4]
print("Is list object a Iterable object?:%s"%isinstance(aIt,Iterable))
print("----------------SPLIT LINE----------------")
# 使用对象内部的__ iter __方法或者Python内置的iter函数都可以生成该对象的迭代器
iterator1 = aIt.__iter__()
print(iterator1)
print(isinstance(iterator1,Iterator))
iterator2 = iter(aIt)
print(iterator2)
print(isinstance(iterator2,Iterator))
print("----------------SPLIT LINE----------------")
# 使用迭代器对象的__ next __方法和Python内置的next函数都可以得到迭代器对象的下一个值
print("iterator1.__next__() is %s"%iterator1.__next__())
print("next(iterator1) is %s"%next(iterator1))
print("iterator2.__next__() is %s"%iterator2.__next__())
print("next(iterator2) is %s"%next(iterator2))
print("----------------SPLIT LINE----------------")
"""
for 迭代是上述示例的一层封装
"""
for i in aIt:
print(i)
Is list object a Iterable object?:True
----------------SPLIT LINE----------------
True
True
----------------SPLIT LINE----------------
iterator1.__next__() is 1
next(iterator1) is 2
iterator2.__next__() is 1
next(iterator2) is 2
----------------SPLIT LINE----------------
1
2
3
4
**注:**但是如果不首先调用__ iter __ 方法或者iter函数将可被迭代对象转化为迭代器,则会产生错误:
next(aIt)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
----> 1 next(aIt)
TypeError: 'list' object is not an iterator
aIt.__next__()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in ()
----> 1 aIt.__next__()
AttributeError: 'list' object has no attribute '__next__'
产生错误的原因在于list对象内部并没有实现__ next __ 方法,因此只是一个可迭代对象而非迭代器对象。因此需要使用__ iter __ 方法或者iter函数生成迭代器对象。
hasattr(aIt,"__iter__")
True
hasattr(aIt,"__next__")
False
因此,想要让可迭代对象可以真正进行迭代,只需要让 __ iter __ 方法进行返回一个迭代器即可:
class ListIterator(Iterator):
def __init__(self,list_obj):
self.list_obj = list_obj
self.index_num = 0
def __next__(self):
if self.index_num < len(self.list_obj):
ret = self.list_obj[self.index_num]
self.index_num += 1
return ret
else:
raise StopIteration
class Dog(object):
def __init__(self,names):
self.names = names
def __iter__(self):
return ListIterator(self.names)
dog = Dog(["Alice","Bob","Cindy"])
for i in dog:
print(i)
Alice
Bob
Cindy
isinstance(dog,Iterable)
True
isinstance(dog,Iterator)
False
isinstance(iter(dog),Iterator)
True
总结如下:
参考链接:Python 迭代器(Iterator)
class ListIterator(Iterator):
def __init__(self,list_obj):
self.list_obj = list_obj
self.index_num = 0
self.isAlreadyDone = list_obj.isAlreadyDone
def __next__(self):
if self.isAlreadyDone == 1:
raise StopIteration
else:
if self.index_num < len(self.list_obj.names):
ret = self.list_obj.names[self.index_num]
self.index_num += 1
return ret
else:
self.list_obj.isAlreadyDone = 1
raise StopIteration
class Dog(object):
def __init__(self,names):
self.names = names
self.isAlreadyDone = 0
def __iter__(self):
return ListIterator(self)
dog = Dog(["Alice","Bob","Cindy"])
for i in dog:
print(i)
Alice
Bob
Cindy
# 将返回空
for i in dog:
print(i)
上述代码示例中的dog对象正是一个生成器对象。由于for循环对其进行迭代时,每次都会调用dog对象的 __ iter __ 方法,但却不会重新调用dog的__ init __ 方法对其进行重新创建,因此,只需要在dog中加入一个判断是否已经完成首次迭代的属性,并且在 __ iter __ 方法中将dog对象传入迭代器中,那么迭代器对象不管被建立几次,其中的判断属性isAlreadyDone则不会受到影响。
在Python中,生成器大致可以分成两类,生成器函数以及生成器解析式:
"""
此时,像这种带有yield的“函数”,其本质上是一个可以随时挂起的生成器,就不再是函数了。
我们可以像使用迭代器那样来使用这种生成器函数,其运行过程就是:每当执行到yield语句则返回一次迭代的结果,
然后内部挂起,当下次next的调用时继续从下次挂起的位置执行,直到yield。如此循环往复。
"""
def g():
for i in range(10):
yield 2*i
g = g()
for i in g:
print(i)
0
2
4
6
8
10
12
14
16
18
"""
生成器解析器的语法和列表解析式几乎一致,但是用( )进行开始和结尾,表示返回的是一个生成器,
这里要注意,此种语法并非元组解析式
"""
g = (i*2 for i in range(10))
g
at 0x0000027FA2AAAE58>
g.__next__()
0
next(g)
2
for i in g:
print(i)
4
6
8
10
12
14
16
18
for i in g:
print(i)
总结如下: