迭代器
什么是迭代协议?
迭代器是什么?迭代器是访问集合内元素的一种方式,一般用来遍历数据
迭代器和以下标的访问方式不一样。迭代器是不能返回的,迭代器提供了一种惰性方式访问数据
任何实现了iter或者getitem的都是可迭代对象
class Company(object):
def __init__(self, employee_list):
self.employees = employee_list
def __getitem__(self, item):
return self.employees[item]
company = Company(['张三', '李四', '王五'])
print(isinstance(company, Iterable))
# 执行结果:False
print(isinstance(company, Iterator))
# 执行结果:False
for c in company:
print(c)
执行结果:
张三
李四
王五
对于for循环来说,首先寻找iter方法,如果没有iter方法,那么就会去寻找getitem方法,这个方法是用来定义序列用的,
如果两个方法都没有,那么就说这个对象是不可迭代的。只要实现了这两个方法中的其中一个,就证明这个对象是可迭代对象。
如果有iter方法,就会得到一个迭代器对象,然后调用迭代器的next方法,获取元素,直到抛出StopIteration异常为止,for循环本身
会对这种异常作出处理。如果有getitem方法,那么就从下标0开始获取数据。
疑问:只有getitem的类的实例是属于可迭代对象,但用isinstances测试collections.Iterable是不能通过的,可以通过iter函数来测试,
如果没报错就说明是可迭代对象,然后生成一个没有next属性的迭代器。
print(dir(company))
'''
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'employees']
'''
迭代器需要实现iter和next,iter用来返回一个迭代器,next用来获取下一个元素和抛出StopIteration的异常。
备注:内置函数iter()调用的是iter方法,next()调用的是next方法
class Company(object):
def __init__(self, employee_list):
self.employees = employee_list
def __iter__(self):
return MyIterator(self.employees)
class MyIterator():
def __init__(self, iter_list):
self.iter_list = iter_list
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
res = self.iter_list[self.index]
except IndexError:
raise StopIteration
self.index += 1
return res
company = Company(['张三', '李四', '王五'])
print(isinstance(company, Iterable))
# 执行结果:True
print(isinstance(company, Iterator))
# 执行结果:False
my_iterator = MyIterator(['张三', '李四', '王五'])
print(isinstance(my_iterator, Iterable))
# 执行结果:True
print(isinstance(my_iterator, Iterator))
# 执行结果:True
for em in company:
print(em)
'''
执行结果
张三
李四
王五
'''
生成器
生成器函数:函数里面只要有yield关键字,那么这就是一个生成器函数
生成器函数最开始调用的时候,返回的是一个生成器对象,在python编译字节码的时候就产生了这个生成器对象
生成器函数也可以return一个值
生成器函数会在内部记录函数执行的字节码的位置,生成器函数也是分配在堆内存当中的
调用生成器函数,函数并不会马上执行,调用next方法或者用for驱动生成器的执行.
如果next方法取不到值了,则要给一个默认值,否则会报StopIteration的错误。
在生成器函数中,函数执行遇到yield会挂起,返回yield右边的值,直到下一次生成器再次被驱动。send方法也可以驱动生成器函数。
def foo():
yield 1
name = 'bobby'
yield 2
age = 18
return 30
f = foo()
print(isinstance(f, Generator))
# 执行结果:True
print(next(f))
# 执行结果:1
print(next(f))
# 执行结果:2
print(next(f, 'Over'))
捕获生成器的返回值
def foo():
yield 1
name = 'bobby'
yield 2
age = 18
return 30
f = foo()
while True:
try:
x = next(f)
print(x)
except StopIteration as e:
print('StopIteration:',e.value)
break
'''
执行结果:
1
2
StopIteration: 30
'''s