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

    Python可迭代对象、迭代器和生成器

    总览:可迭代对象、迭代器、生成器之间的关系

    迭代器和生成器
    • 可迭代对象:可以进行for循环的都是可迭代对象,原因是其内部实现了一个__iter__方法
    • 迭代器:能够用next()函数,都是迭代器对象,其内部实现了__iter____next__方法
    • 生成器:元组推导式和函数里使用yield的函数都是生成器
    • 生成器是一种特殊的迭代器,迭代器也是可迭代对象,可迭代对象可通过iter()函数转化为成为迭代器
    • 容器(列表,元组,字典,集合)是可迭代对象,可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素,从而支持遍历。

    1.可迭代对象和迭代器

    1.1 基础概念
    可迭代对象和迭代器
    • 所有的可迭代对象均内置了_iter_()方法,调用iter()方法,返回值就是一个迭代器
    • 迭代器中内置了_next_()方法,调用该方法,会返回迭代器对象的每个元素,因此迭代就是从迭代器中取元素的过程
    • python中的列表、字典、元组、字符串都是可迭代对象,可迭代对象都可以用for循环实现迭代遍历。
    1.2 判断
    from collections.abc import Iterable, Iterator
    a = [1, 2, 3]
    b = iter(a) # 可迭代对象调用内置iter()方法返回一个迭代器
    isinstance(a, Iterable)
    isinstance(b, Iterator)
    isinstance(b, Iterable)
    
    1.3 for循环本质

    调用可迭代对象的_iter_()方法,得到该对象对应的迭代器对象,然后无限调用_next_()方法,得到对象中的每一个元素,直到Stopiteration异常,代表迭代器中已无下一个元素,for循环自动处理该异常,跳出循环。

    # 字典的键,值,键值对都是可迭代对象
    for key in {'one':1, 'two':2}:
        print(key)
    # 字符串是可迭代对象
    for char in "123":
        print(char)
    # 打开的text同样是可迭代对象
    for line in open("myfile.txt"):
        print(line, end='')
    
    1.4 不想用for循环迭代了,如何使用迭代器?
    1. 先调用容器(以字符串为例)的iter()函数
    2. 再使用 next() 内置函数来调用 __next__() 方法
    3. 当元素用尽时,__next__() 将引发 StopIteration 异常
    使用迭代器
    1.5 列表推导式
    • []
    li = [i for i in range(10)]
    print(li)
    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    # 每个元素在生成后都会存在内存中,如果元素很多,就会占用很大的存储空间
    

    迭代器实现一个列表:[i for i in range(1000)]

    2. 生成器Generator

    2.1 概念

    在Python中,我们把一边循环一边计算的机制,称为生成器。生成器也是一种迭代器,但由于它们并没有把所有的值存在内存中,而是在运行时生成值,因此只能迭代一次。

    使用生成器,可以写出来更加清晰的代码;合理使用生成器,可以降低内存占用、优化程序结构、提高程序速度。

    2.2 如何实现和使用?
    2.2.1 生成器表达式(元组推导式)
    • ()
    ge = (i for i in range(10))
    print(li)
    # <generator object <genexpr> at 0x7f4f446a21d0>
    next(ge)
    # 0
    
    • 生成器表达式可以认为是一种特殊的生成器函数,返回生成器对象,一次只返回一个值
    2.2.2 带有关键字yield的函数
    • 程序运行到yied这一行的时候,生成器调用next()函数生成一个值,同时暂停程序,直到下次调用next()函数时才激活,从上次离开的位置恢复执行
    def reverse(data):
        for index in range(len(data)):
            yield data[index] 
        print("大大")
    # reverse('golf'), 此条语句返回一个生成器对象(也是可迭代对象),for循环实现遍历没毛病
    for char in reverse('golf'):
        print(char)
    # 输出
    g
    o
    l
    f
    大大
    # 遍历方法2
    char = reverse('golf') # 返回一个生成器对象,<generator object reverse at 0x7f71c8124250>
    print(next(char))
    print(next(char))
    print(next(char))
    print(next(char))
    print(next(char))
    # 输出
    g
    o
    l
    f
    大大
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    

    3. 应用举例

    3.1 给定一个list和一个指定数字,求这个数字在list中的位置
    # 常规for循环遍历
    def index_normal(L, target):
        result = []
        for i, num in enumerate(L):
            if num == target:
                result.append(i)
        return result
    
    print(index_normal([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2))
    
    # 使用生成器
    def index_generator(L, target):
        for i, num in enumerate(L):
            if num == target:
                yield i
    # index_generator会返回一个生成器对象,需要使用list转换为列表后,才能print输出
    print(list(index_generator([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2)))
    # 输出
    [2, 5, 9]
    
    
    3.2 给定两个序列,判定第一个是不是第二个的子序列

    解析:序列就是列表,子序列指的是一个列表的元素在第二个列表中都按顺序出现,但是并不必挨在一起

    def is_subsequence(a, b): 
        b = iter(b) # 把列表b转化成一个迭代器
        return all(i in b for i in a) 
        # (i for i in a),将列表a初始化为一个生成器,可以遍历对象a
        # i in b,判断生成器next()函数遍历a的指是否在迭代器b调用next()得到的对象中
        # all函数,判断一个迭代器的元素是否全部为True
    
    print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5]))
    print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5]))
    # 输出
    True
    False
    
    3.3 计算0-9数字的平方和
    sum(i*i for i in range(10))  
    # 285
    
    3.4 web自动化测试pytest框架,测试夹具设置前后置条件
    @pytest.fixture(scope="class")
    def browser():
        """启动和关闭浏览器"""
        # 初始化浏览器
        driver = webdriver.Chrome()
        # 设置隐式等待
        driver.implicitly_wait(10)
        # 浏览器页面最大化
        driver.maximize_window()
        # 返回一个浏览器对象
        yield driver
        driver.quit()
    

    参考文章:

    [1]https://zhuanlan.zhihu.com/p/76831058

    [2]https://blog.csdn.net/baidu_28289725/article/details/80622454

    [3]https://time.geekbang.org/column/article/101521?utm_source=pinpaizhuanqu&utm_medium=geektime&utm_campaign=guanwang&utm_term=guanwang&utm_content=0511

  • 相关阅读:
    NSDate的处理:前一天、后一天等关于时区偏移的处理以及在数据库中的使用
    《powershell 的版本号所引起的载入 FSharp 编译器问题》基本解决
    hdu 2055 An easy problem (java)
    昨天登陆页面,无法进入后台,今天攻克了
    关于ubuntu下qt编译显示Cannot connect creator comm socket /tmp/qt_temp.xxx/stub-socket的解决的方法
    (转)Struts2的拦截器
    (转)Struts2的标签库
    (转)OGNL与值栈
    (转)Struts2访问Servlet的API及......
    (转)Struts2快速入门
  • 原文地址:https://www.cnblogs.com/donghe123/p/13282694.html
Copyright © 2011-2022 走看看