zoukankan      html  css  js  c++  java
  • 可迭代对象、迭代器和生成器

    迭代(Iteration)

    ​ 当我们使⽤⼀个循环来遍历某个东西时,这就叫⼀个迭代。

    可迭代对象(Iterable)

    ​ ⼀个可迭代对象是Python中任意的对象,只要它定义了可以返回⼀个迭代器的__iter__
    ⽅法,或者定义了可以⽀持下标索引的__getitem__⽅法。简单说,⼀个可迭代对象,就是任意的对象,只要它能给我们提供⼀个迭代器。

    container__iter__() 返回一个迭代器对象。 该对象需要支持迭代器协议。 如果容器支持不同的迭代类型,则可以提供额外的方法来专门地请求不同迭代类型的迭代器。

    迭代器(Iterator)

    ​ ⼀个迭代器是任意⼀个对象,只要它定义了⼀个next(Python2) 或者__next__⽅法。

    iterator.__next__()从容器中返回下一项。 如果已经没有项可返回,则会引发 StopIteration 异常。

    特点: 节省内存,惰性机制,不能反复, 只能向下执行.

    • 迭代器是可迭代的,所有的迭代器都是它们自己的迭代器
    • 迭代器没有长度,它们不能被索引
    • 可以把迭代器看作是惰性迭代器,它们是一次性使用,这意味着它们只能循环遍历一次。

    文件迭代器

    #手动遍历
    f = open('xxx','r',encoding='utf8')
    f.readline()        #每次调用readine方法,就会到下一列,最后一行使用得到空字符
    #使用f.__next__()可以达到同样的效果,不同的是,已达到最后一行,继续使用__next__会引发StopIteration异常,捕获即可解决。
    #文件对象本身就是一个迭代器
    

    #常用for循环迭代,调用内部的__next__
    for i  f:
        xxxxx
    
    列表

    列表以及很多其他的内置对象,不是自身的迭代器,所以支持多次打开迭代器。

    L = [1,2,3]
    L.__next__()
    #AttributeError: 'list' object has no attribute '__next__'
    
    lst = [1,2,3]
    lst_iter = lst.__iter__()
    #while循环+迭代器模拟登录
    while True:
    	try:
    		i = lst_iter.__next__()
    		print(i)
    	except StopIteration:
    		break
    
    L = [1,2,3]
    a = L.__getitem__(2)  # 支持下标索引,L[2]
    print(a)
    # 3
    
    range

    内置函数range,返回一个可迭代对象,根据需要产生范围中的数字,而不是在内存中构建一个结果列表

    >>> range(0,7)
    range(0, 7)
    >>> r = range(0,7)
    >>> r[3]
    3
    >>> len(r)   
    7
    >>> list(range(0,7))    #强制转换成列表
    [0, 1, 2, 3, 4, 5, 6]
    
    map、zip和filter

    map、zip和filter和range不同,它们都是自己的迭代器。range支持len和索引,而它们不支持。

    >>> M
    <map object at 0x0401A870>
    >>> M.__next__()
    1
    >>> N = M
    >>> N.__next__()
    0
    
    自定义可迭代对象

    构建一个自定义容器对象,

    class Node:
        def __init__(self,*value):
            self._children = list(value)
        def __iter__(self):
            return iter(self._children)
    N = Node(1,2,3,4,5)
    for i in N:
        print(i,end = ' ')
    #1 2 3 4 5 
    # #只需要定义一个__iter__方法,将迭代操作代理到容器内部的对象上
    去。
    

    生成器

    生成器本质就是迭代器,生成器的两种构建方式:1.生成器函数 2.生成器表达式。

    • 生成器函数:编写常规的def语句,使用yield语句返回一个结果,在每个结果之间挂起和继续它们的状态
    • 生成器表达式:返回一个按需产生结果的一个对象,而不是构建一个结果列表。

    二者都不会一次性构建一个列表,节省了内存空间,将计算事件分散到各个结果请求。

    生成器函数
    def gensquares(n):
        for i in range(n):
            yield i ** 2
    def gensquares(n):
        for i in range(n):
            yield i ** 2
    g = gensquares(3)
    print(g)
    #<generator object gensquares at 0x03982B30>
    print(g.__next__())
    print(g.__next__())
    #
    0
    1
    
    send和next

    调用g.send(value)发送给生成器g,并且生成器中的yield表达式返回了为了发生而传入的值。

    def gen():
        for i in range(5):
            x =  yield i
            print(x)
    G = gen()
    g = G.__next__() 
    print(g)     
    G.send(9)    # 必须先调用__next__() 
    g = G.__next__()
    print(g)
    #结果:
    0
    9
    None  #x接收send发送的值,没有发送默认为None
    2
            
    
    生成器表达式
    G = (x*2 +1 for x in range(4))
    G.__next__()
    

    def add(a, b):
    	return a + b
    def test():
    	for r_i in range(4):
    		yield r_i
    g = test()
    for n in [2, 10]:
    	g = (add(n, i) for i in g)
    print(list(g))
    #[20,21,22,23]
    不要局部地关注for in g,  (add(n, i) for i in g)这个表达式整体是一个生成器
    并没有调用__next__方法。for每循环一次,n被重新赋值,并对g(表达式左边)重新赋值,生成器表达式随之发生改变。
    第一次  n = 2,g = (add(n, i) for i in text())
    第二次  n = 3,g = (add(n, i) for i in ((add(n, i) for i in text())))
    			..........
    循环结束时	n = 10  g = (add(n, i) for i in ((add(n, i) for i in text())))
    
  • 相关阅读:
    Python学习笔记(11)递归与匿名函数
    Python学习笔记(10)局部变量、全局变量、常量
    Python学习笔记(8)函数、位置参数、可变参数、关键字参数
    Pyhthon学习笔记(7)三元表达式及列表生成式
    Python自动化学习笔记(5)字符串常用的方法
    Python自动化学习(4)列表与字符串的切片操作
    python自动化学习笔记(3)列表list和字典dict
    python自动化学习笔记(2)字符串格式化输出与条件判断及循环语句
    Python自动化学习笔记(1)认识接口测试以及postman、Charles工具简单应用
    《软件测试的艺术》 阅读整理(二)
  • 原文地址:https://www.cnblogs.com/notfind/p/11520124.html
Copyright © 2011-2022 走看看