• 迭代器-Iterator


    可以直接作用于for循环的数据类型有以下两类

    一类是基础数据类型里的str,list,tuple,dict,set

    另一类是generator

    这些可以直接作用于for循环的对象统称为可迭代对象 Iterable 

    可以使用isinstance()判断一个对象是否是Iterable对象:

     1 from collections import Iterable
     2 
     3 
     4 def test_yield():
     5     yield 1
     6     yield 2
     7 
     8 print(type([]), isinstance([], Iterable))
     9 print(type(()), isinstance((), Iterable))
    10 print(type('abc'), isinstance('abc', Iterable))
    11 print(type({}), isinstance({}, Iterable))
    12 print(type(100), isinstance(100, Iterable))
    13 result = test_yield()
    14 print(type(result), isinstance(result, Iterable))

    以下是结果:

    1 <class 'list'> True
    2 <class 'tuple'> True
    3 <class 'str'> True
    4 <class 'dict'> True
    5 <class 'int'> False
    6 <class 'generator'> True

    而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

    可以被next()函数调用并不断返回下一个值的对象称为迭代器 Iterator 。

    可以使用isinstance()判断一个对象是否是Iterator对象:

    1 print(isinstance((x for x in range(10)),Iterator))
    2 print(type(result), isinstance(result, Iterator))
    3 print(type([]), isinstance([], Iterator))

    以下是运行结果:

    1 True
    2 <class 'generator'> True
    3 <class 'list'> False

    从上面的结果看,生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

    可以使用内置函数iter()将list,dict,str,tuple等转化成Iterator print(type(iter([])), isinstance(iter([]), Iterator)) 

    那为什么list,tuple,dict,str是Iterable,却不是Iterator呢?

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    Python的for循环本质上就是通过不断调用next()函数实现的,

    例如对于 number_list = [1, 2, 3, 4, 5] ,下面两段代码是等价的:

    1 for item in number_list:
    2     print(item)
    1 it = iter(number_list)
    2 while True:
    3     try:
    4         number = next(it)
    5         print(number)
    6     except StopIteration:
    7         break

     但是我们如果对number_list使用next()方法却会报错:

    1 next(number_list)
    2 TypeError: 'list' object is not an iterator

    代理迭代

    假如我们自定义了一个类,我想直接在这个类的对象进行上执行迭代操作:

    1 class Node(object):
    2     def __init__(self, value):
    3         self.__value = value
    4         self.__children = []

    实际上我们只需要定义一个 __iter__(self) 方法,将迭代操作代理到类内部的可转化为迭代器的字段上去:

     1 class Node(object):
     2     def __init__(self, value):
     3         self.__value = value
     4         self.__children = []
     5 
     6     def add_child(self, node):
     7         self.__children.append(node)
     8 
     9     def set_value(self, value):
    10         self.__value = value
    11 
    12     def get_value(self):
    13         return self.__value
    14 
    15     def __iter__(self):  # __iter__() 方法只是简单的将迭代请求传递给内部的__children    
    16         return iter(self.__children)

    探讨:

    Python 的迭代器协议需要__iter__() 方法返回一个实现了__next__() 方法的迭代
    器对象。如果你只是迭代遍历其他容器的内容,你无须担心底层是怎样实现的。你所
    要做的只是传递迭代请求既可。
    这里的iter() 函数的使用简化了代码,iter(s) 只是简单的通过调用
    s.__iter__()方法来返回对应的迭代器对象,就跟len(s) 会调用s.__len__()原理
    是一样的。

    小结

    -凡是可作用于for循环的对象都是Iterable类型;

    -凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    -集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

  • 相关阅读:
    [复变函数]第07堂课 2.2 初等解析函数
    [家里蹲大学数学杂志]第237期Euler公式的美
    [家里蹲大学数学杂志]第287期复变函数讲义
    [家里蹲大学数学杂志]第253期实变函数讲义
    模仿王者荣耀的实时阴影
    Android 识别身份证号码(图片识别)
    基于swiper的移动端H5页面,丰富的动画效果
    基于skitter的轮播图炫酷效果,幻灯片的体验
    基于canvas的原生JS时钟效果
    .net core 实现简单爬虫—抓取博客园的博文列表
  • 原文地址:https://www.cnblogs.com/z-joshua/p/6370631.html
Copyright © 2020-2023  润新知