可迭代对象:实现__iter__方法的类的实例对象。 迭代器:实现__iter__和__next__方法的类的实例对象,两个方法缺一不可。 生成器:调用含有yield关键字的函数会返回一个生成器对象。
迭代器一定是可迭代对象,可迭代对象不一定是迭代器。 生成器是一种特殊的迭代器。
字符串对象、列表对象、字典对象、元组对象、集合对象都是可迭代对象,但不是迭代器。因为它们都内置实现了__iter__。
from collections import Iterator, Iterable str_test = "zhangsan" list_test = ["zhangsan", "lisi", "wangwu"] dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu"} tuple_test = ("zhangsan", "lisi", "wangwu") set_test = {"zhangsan", "lisi", "wangwu"} print(isinstance(str_test, Iterable)) print(isinstance(str_test, Iterator)) print(isinstance(list_test, Iterable)) print(isinstance(list_test, Iterator)) print(isinstance(dict_test, Iterable)) print(isinstance(dict_test, Iterator)) print(isinstance(tuple_test, Iterable)) print(isinstance(tuple_test, Iterator)) print(isinstance(set_test, Iterable)) print(isinstance(set_test, Iterator)) """ 运行结果: True False True False True False True False True False Process finished with exit code 0 """自定义迭代器需注意三点:
必须实现__iter__()方法必须实现__next__()方法在__next__()方法中当最后一个元素被迭代出后抛出StopIteration异常转该地址查看解析
__getitem__:如果类把某个属性定义为序列,可以使用__getitem__输出序列属性中的某个元素。可以认为绑定__getitem__方法的实例对象为自定义序列对象。
yield详解
迭代协议:绑定__iter__方法的实例对象称为可迭代对象。
以下是 iter方法的语法:
iter(object[, sentinel])
object:支持迭代协议的实例对象或支持序列协议的实例对象,否则会返回TypeError异常。
sentinel:传递了第二个参数时。(i) 参数 object 必须是一个能够对内部状态进行维护可调用的对象(如,闭包内函数对象或绑定的__call__方法的实例对象);(ii) iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__方法时,都会调用 object;(iii) 当__next__的返回值等于哨兵时,就会抛出异常StopIteration。
【注】序列协议:绑定__getitem__方法的实例对象称为自定义序列对象。
只绑定__iter__方法的实例对象一般结合迭代器使用。
class StudentList(object): # 创建一个类,为了创建对应的可迭代对象 def __init__(self): self.items = [] # 定义一个属性是空列表 def append(self, name): # 定义方法可以传参数添加到空列表 self.items.append(name) def __iter__(self): # 定义iter方法,返回的是对应的可迭代器 print("++__iter__++") return ListIter(self.items) class ListIter(object): # 自定义迭代器:作用是记录迭代位置和帮助可迭代对象返回数据 def __init__(self, items): self.items = items # 保存数据 self.index = -1 # 记录下标位置 def __iter__(self): return self def __next__(self): self.index += 1 # 每次使用,下标即+1 if self.index < len(self.items): return self.items[self.index] # 返回下标数据 else: raise StopIteration # 抛出异常 if __name__ == '__main__': my_list = StudentList() my_list.append("zhangsan") my_list.append("lisi") my_list.append("wangwu") my_list.append("zhaoliu") for name in my_list: print(name) """ 运行结果: ++__iter__++ zhangsan lisi wangwu zhaoliu Process finished with exit code 0 """总结:
对于函数来说,闭包可以实现内部函数状态的维护。对于对象来说,可以通过属性实现对某个方法的内部状态的维护。