python--基础知识点--(1)可迭代对象、迭代器、生成器(2)辨析

    技术2022-07-11  95

    一、概念及关系

    1、概念

    可迭代对象:实现__iter__方法的类的实例对象。 迭代器:实现__iter__和__next__方法的类的实例对象,两个方法缺一不可。 生成器:调用含有yield关键字的函数会返回一个生成器对象。

    2、关系

    迭代器一定是可迭代对象,可迭代对象不一定是迭代器。 生成器是一种特殊的迭代器。

    二、示例

    1、可迭代对象

    字符串对象、列表对象、字典对象、元组对象、集合对象都是可迭代对象,但不是迭代器。因为它们都内置实现了__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 """
    2、迭代器
    (1) iter、__next__自定义迭代器
    class Students: def __init__(self, names): self.names = names self.counter = -1 def __iter__(self): print("+++__iter__+++") return self def __next__(self): self.counter += 1 if self.counter >= len(self.names): raise StopIteration return self.names[self.counter] if __name__ == '__main__': names = ["zhangsan", "lisi", "wangwu"] students = Students(["zhangsan", "lisi", "wangwu"]) for name in students: print(name) """ for...in..过程等同于以下过程 iter(students) # 当使用while运行迭代器时可以去掉这条语句,因为students该对象本身就是迭代器,运行结果中也不会有第一行+++__iter__+++ while True: try: print(next(students)) except StopIteration as e: break """ from collections import Iterable, Iterator print(isinstance(students, Iterator)) print(isinstance(students, Iterable)) """ 运行结果: +++__iter__+++ zhangsan lisi wangwu True True Process finished with exit code 0 """

    自定义迭代器需注意三点:

    必须实现__iter__()方法必须实现__next__()方法在__next__()方法中当最后一个元素被迭代出后抛出StopIteration异常
    (2)将绑定__getitem__方法的实例对象通过iter转变为迭代器

    转该地址查看解析

    __getitem__:如果类把某个属性定义为序列,可以使用__getitem__输出序列属性中的某个元素。可以认为绑定__getitem__方法的实例对象为自定义序列对象。

    (3) 将序列转化为迭代器
    # 以列表为例 list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"] list_test = iter(list_test) while True: try: print(next(list_test)) except StopIteration as e: break """ 运行结果: zhangsan lisi wangwu zhaoliu Process finished with exit code 0 """ # 以字典为例 dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu""name3": "zhaoliu"} dict_test = iter(dict_test) while True: try: print(next(dict_test)) except StopIteration as e: break """ 运行结果: name0 name1 name2 name3 Process finished with exit code 0 """
    3、生成器
    def Test(tests): for test in tests: yield test if __name__ == '__main__': list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"] test_gen = Test(list_test) for test in test_gen: print(test) """ 运行结果: zhangsan lisi wangwu zhaoliu Process finished with exit code 0 """

    yield详解

    三、辨析__iter__、iter

    1、iter

    迭代协议:绑定__iter__方法的实例对象称为可迭代对象。

    2、iter

    以下是 iter方法的语法:

    iter(object[, sentinel])

    object:支持迭代协议的实例对象或支持序列协议的实例对象,否则会返回TypeError异常。

    sentinel:传递了第二个参数时。(i) 参数 object 必须是一个能够对内部状态进行维护可调用的对象(如,闭包内函数对象或绑定的__call__方法的实例对象);(ii) iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__方法时,都会调用 object;(iii) 当__next__的返回值等于哨兵时,就会抛出异常StopIteration。

    【注】序列协议:绑定__getitem__方法的实例对象称为自定义序列对象。

    (1)只有第一个参数object出现时

    只绑定__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 """
    (2) 第二个参数sentinel出现时
    # (i) object为闭包内函数对象时 def function_out(list_): index = -1 def function_in(): nonlocal index index += 1 result = list_[index] # 此处可做一些其它操作 return result return function_in if __name__ == '__main__': names = ["zhangsan", "lisi", "wangwu", "zhaoliu"] students = function_out(names) for name in iter(students, "wangwu"): # for...in...内部自动会处理StopIteration异常 print(name) """ 运行结果: zhangsan lisi Process finished with exit code 0 """ # (2) object为绑定的__call__()方法的实例对象时 class ListIter(object): def __init__(self, items): self.items = items self.index = -1 def __call__(self): self.index += 1 result = self.items[self.index] # 此处可以做一些其它操作 return result if __name__ == '__main__': names = ["zhangsan", "lisi", "wangwu", "zhaoliu"] students = ListIter(names) for name in iter(students, "wangwu"): print(name) """ 运行结果: zhangsan lisi Process finished with exit code 0 """

    总结:

    对于函数来说,闭包可以实现内部函数状态的维护。对于对象来说,可以通过属性实现对某个方法的内部状态的维护。
    Processed: 0.013, SQL: 9