• python函数式编程之迭代器


    什么是迭代器

    顾名思义,就是更新换代的意思

    python中的迭代器就是根据上一个结果生成下一个结果,一直循环往复不断重复的过程

    迭代器有两个特点:

    • 1.不断重复同一个过程
    • 2.根据上一个结果生成下一个结果

    迭代器的定义

    先来看两个例子

    代码一:

    while True:
        cmd = input("input your command: ").strip()
        print(cmd)
    

    代码二:

    l1 = ["a", "b", "c", "d"]
    count = 0
    while count < len(l1):
        print(l1[count])
        count += 1
    

    在代码一中,让用户不断输入命令,然后打印用户输入的命令,这是一个不断重复的过程,但是后一个结果跟前一个结果没有什么联系,所以代码一不是迭代器

    在代码二中,先定义一个列表l1和count,在count的值小于列表l1的长度中,打印列表中count索引的值,然后count的值加1,这几行代码符合迭代器的定义

    代码二的执行过程:

    首先,打印列表l1中count索引的值,这是一个不断重复的过程
    然后,每循环一次,count的值就在以前的基础上增加1,直到count的值等于列表l1的长度时,循环中止
    

    所以代码一不是迭代器,代码二才是符后迭代器的定义标准

    迭代器的作用

    python中常见的数据类型包括字符串,列表,元组,字典,集合,文件

    我们知道,python中的数据类型又分为有序和无序

    对于有序数据类型,可以如上面的代码二所示,使用索引遍历有序数据类型中的元素

    而对于无序数据类型,就不可以使用索引来遍历其中的元素了,此时可以使用for循环来遍历其中的元素

    现在来看看for循环到底做了哪些事,可以取出无序数据类型中的元素

    dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, }
    
    for k in dic1:
        print(k)
    

    执行上面的程序,可以打印出字典dic1中所有的键

    实际上,python为了提供一种不依赖于索引的迭代方式,python会为一些对象内置__iter__方法

    在python中,如果一个对象有__iter__方法,那么这个对象就是可迭代对象
    执行obj.__iter__()方法得到的结果就是迭代器
    

    所以python中的迭代器,都会有__iter__方法和__next__方法

    以上面定义的dic1为例

    dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, }
    
    i = dic1.__iter__()			# dic1.__iter__方法执行结果得到一个迭代器i
    print(i)					# 打印迭代器,得到结果:<dict_keyiterator object at 0x0000000002DBD278>
    print(i.__next__())			# 执行迭代器i中的__next__方法,得到dic1中的一个元素,然后打印迭代出的元素
    print(i.__next__())			# 再次执行迭代器的__next__方法,得到dic1的第二个元素,然后打印出来
    print(i.__next__())			# 第三次执行迭代器的__next__方法,得到dic1的第三个元素,然后打印出来
    

    由于python的字典是无序的数据类型,所以每次得到的dic1中的元素可能是不相同的

    执行三次__next__方法,得到的结果如下

    a
    b
    c
    

    上面dic1的长度为4,如果执行5次__next__方法,会出错什么结果

    dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, }
    
    i = dic1.__iter__()
    print(i.__next__())
    print(i.__next__())
    print(i.__next__())
    print(i.__next__())
    print(i.__next__())
    

    程序执行结果

    a
      File "D:python3libunittestloader.py", line 153, in loadTestsFromName
    b
    
        module = __import__(module_name)
    c
    
      File "E:python_learnpy_code	est.py", line 21, in <module>
    d
        print(i.__next__())
    StopIteration
    

    可以看到,python解释器在执行第五次__next__方法时,抛出了StopIteration的错误,这说明如果执行__next__方法的次数超出迭代器的长度时,python解释会抛出异常

    迭代器的优缺点

    迭代器的优点

    1.提供一种不依赖于索引的取值方式
    2.提供惰性计算,每执行一次__next__方法,只会从迭代器中取出一个值,不管这个数据长度有多大,使用迭代器取值时,每取出一个值,占用的内存空间都一个元素的大小,非常节省内存空间
    

    迭代器的缺点

    1.取值比较麻烦。如果想用迭代器的方式取出列表中的第三个值,必须调用三次__next__方法,才能取出第三个值,而前两次取出的值实际上是没有作用的
    2.一次性的,只能向后迭代,不能回退。如果运行两次__next__方法后,就不可能回退再去了迭代器的第一个值
    3.不能获取到迭代器的长度,只能不停执行__next__方法,直到出现StopIteration的提示,此时才能知道迭代器的长度
    

    for循环的执行过程

    定义一个列表,使用for循环遍历取出列表中的值

    l1 = ['a', 'b', 'c', 'd']
    
    for i in l1:
        print(i)
    

    在for循环的执行过程中,实际上for循环是把in后面的对象执行__iter__方法,得到一个迭代器对象,然后不停执行迭代器对象中的__next__方法,得到元素,然后把迭代出来的元素赋值给i,再调用print方法打印元素i,直到for循环捕捉到StopIteration异常,结束循环,程序停止

    类似于下面的代码

    l1 = ['a', 'b', 'c', 'd']
    
    obj = l1.__iter__()
    
    while True:
        try:
            i = obj.__next__()
            print(i)
        except StopIteration:
            break
    

    判断一个对象是迭代器对象还是可迭代对象

    只要一个对象有__iter__方法,这个对象就是可迭代对象
    一个可迭代对象有__next__方法,这个对象就是迭代器对象
    

    判断python中的字符串,列表,元组,字典和文件对象是否是可迭代对象和迭代器对象

    示例代码

    from collections import Iterable, Iterator
    
    s1 = "hello"
    l1 = ['a', 'b', 'c', 'd']
    t1 = ('a', 'b', 'c', 'd')
    set1 = {'a', 'b', 'c', 'd'}
    dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, }
    f1 = open("db.txt", "w", encoding="utf-8")
    
    print(isinstance(s1, Iterable))
    print(isinstance(l1, Iterable))
    print(isinstance(t1, Iterable))
    print(isinstance(set1, Iterable))
    print(isinstance(dic1, Iterable))
    print(isinstance(f1, Iterable))
    print("*" * 30)
    print(isinstance(s1, Iterator))
    print(isinstance(l1, Iterator))
    print(isinstance(t1, Iterator))
    print(isinstance(set1, Iterator))
    print(isinstance(dic1, Iterator))
    print(isinstance(f1, Iterator))
    

    执行结果:

    True
    True
    True
    True
    True
    True
    ******************************
    False
    False
    False
    False
    False
    True
    

    从上面的例子,可以看出,字符串,列表,元组,集合,字典和文件都是可迭代对象,其中只有文件是迭代器对象

    在上面,我们知道,使用for遍历对象中的值时,是把in后面的对象的变为可迭代对象,然后调用__next__方法取出对象中的元素

    既然文件本身就是迭代器对象,那使用for循环获取文件的内容时,又是怎么做的呢

    先打开一个文件,打印出这个文件对象,再调用文件对象的__iter__方法得到迭代器对象,判断两个对象是否是同一个对象

    f1 = open("db.txt", encoding="utf-8")
    
    print(f1)
    obj = f1.__iter__()
    print(obj)
    
    print(obj is f1)
    

    执行结果

    <_io.TextIOWrapper name='db.txt' mode='r' encoding='utf-8'>
    <_io.TextIOWrapper name='db.txt' mode='r' encoding='utf-8'>
    True
    

    得到结论:

    如果一个对象可以被for循环迭代,则这个对象一定是可迭代对象
    文件对象被执行__iter__方法,得到的结果仍然是一个迭代器对象
  • 相关阅读:
    [算法][递归]求阶乘
    [数据结构]ArrayStack
    [数据结构]Graph
    [数据结构]TrieTree
    [数据结构]UnionFindSet
    [算法]在数组中找到一个局部最小位置
    在二叉树中找到一个节点的后继节点
    [算法]折纸问题
    常用下载方式的区别-BT下载、磁力链接、电驴
    纯文本-FileOutputStream的解码方式
  • 原文地址:https://www.cnblogs.com/renpingsheng/p/8520449.html
Copyright © 2020-2023  润新知