zoukankan      html  css  js  c++  java
  • 迭代器与生成器 (01)

    感觉是这一整周都没有学习和复习了, 一直在忙最近的一个报表开发, 数据处理真的是不容易, 涉及10多张线上, 线下的表, 数据量还挺大, 从 mysql 迁到了 IQ... 主要是数据处理都是要依靠 sql 来进行, 比如去括号呀, 匹配呀这类的... 贼难受, 最有意思的一点是关于匹配, 要进行 4轮匹配, 再全部 union 起来... 虽然性能不太好, 要反复去查表, 但终究功能是可以的, 也看到 sql 的查询强大之处. 相比 Python, 我觉得对于线上大数据量的数据集, 处理就不好弄了, 用 Pandas 读几百万表到 内存 ?? 这就有点难搞, 我也是渐渐觉得, 数据分析, BI, 越发感到 sql 比 Python 更加重要一点, 我当然是两者配合用的呀, 都熟练的.

    然后, 还是来继续抄抄书, 学无止境嘛...

    不用 for 遍历迭代器

    迭代器在 Python 中, 我觉得特别重要, 因为但凡你开始写代码, 都要用到它哇.

    我之前有专门做了笔记关于迭代器: https://www.cnblogs.com/chenjieyouge/p/12274459.html

    • 迭代, 是一个动词, 用谓语. 对一个 集合 对象进行 遍历 的过程就是迭代 (for 循环)
    • 可迭代对象, 能够被 for 循环遍历的对象, 即其构造过程 实现了 __ next __ 方法 和 __ iter __ 方法

    这里就不再解释什么指针, 万物皆对象这些原理了, 总之, __ next __ 方法使当前指针, 指向下一个元素的地址, 而 __ iter __ 方法, 返回 当前元素值, 这就是 for 遍历的原理.

    需求

    遍历一个可迭代对象的所有元素, 但就是不让用 for 循环

    方案

    用 for 循环的原理, 即 __ next __ 方法 或者 内置 next( ) 函数, 二者其实一样的, 我现更偏 对象.__ next __ ( ) 一些

    lst = [1,2,'youge']
    
    it  = iter(lst)
    
    
    # iter() 变为可迭代对象, __next__() 我觉得会更好理解一些
    print(it.__next__())
    
    print(next(it)) 
    
    print(it.__next__())
    print(it.__next__())
    
    1
    2
    youge
    
    # 遍历完了再就会报错哦
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-3-4e885b436bf8> in <module>
          6 print(next(it))
          7 print(it.__next__())
    ----> 8 print(it.__next__())
    
    StopIteration: 
    
    

    再以一个文件对象举例, 遍历每行, 用 __ next __ ( ) 遍历, 并捕获 StepIteration 异常.

    def manual_iter():
        with open("./test.txt") as f:
            try:
                while True:
                    line = f.__next__()
                    print(line)
            except StopIteration:
                pass
                print("over")
    
    # test
    manual_iter()
    
    hello, 
    
      nice to see you 
    
    do you want to drink with me ? 
    
    over
    

    用这种 try..except 来捕捉 StopIteration 的方式, 我工作中是从来没这用过的, 更多是通过 if 的方式来 break .

    # 用 next() 是可以传参的
    
    with open('test.txt') as f:
        while True:
            line = next(f, None)
            if line is None:
                break
            print(line, end = '')
    
    hello, 
      nice to see you 
    do you want to drink with me ? 
    

    自定义可迭代的容器

    简单理解容器对象, 就 list, tuple, dict, str, zip, enumerate 这些.... 可用来装数据的 "容器"

    需求

    构建一个自定义容器, 里面包含有列表, 元组等可迭代对象, 并实现在这容器上进行迭代操作

    方案

    通过在创建类的时候, 实现 __ iter __ 和 __ next __ 方法即可. 当然, 这里的底层结构用 list .

    class Node:
        def __init__(self, value):
            self._value = value, 
            self._items = []
            self._index = 0
            
        def __repr__(self):
            '''打印对象时自动触发, 将任意一个对象,包裹为字符串, 跟 eval() 相逆'''
            return f'Node({self._value})'
        
        def app_item(self, node):
            '''添加元素节点'''
            self._items.append(node)
            
        def __iter__(self):
            """返回自己"""
            return iter(self._items)
        
        def __next__(self):
            """返回当前节点值, 并指向下一个元素节点"""
            if self.index < len(self.items):
                cur_value = self.items[self.index]
                
                # 获取当前值后, 指针再往后移动一次
                self.index += 1
            else:
                raise StopIteration
            return cur_value
            
        
    # test 
    root = Node(0)
    node_01 = Node(1)
    node_02 = Node(2)
    node_03 = Node(3)
    
    root.app_item(node_01)
    root.app_item(node_02)
    root.app_item(node_03)
    
    # 能够 for 的前提是实现了 __iter__ 和 __next__ 方法哦
    for node in root:
        print(node)
        
        
    
    Node((1,))
    Node((2,))
    Node((3,))
    

    用生成器创建自定义迭代模式

    需求

    实现一个自定义迭代模式, 跟普通的内置函数如 range(), reversed() 不一样的方式

    方案

    用生成器 (元组推导式 或 yield ) 来实现, 这里先来写一个生成摸个范围内浮点数的生成器.

    def my_range(start, stop, increment):
        '''生成某个范围内的浮点数'''
        while start < stop:
            yield start 
            start += increment
            
    # test
    for i in my_range(0, 1, 0.25):
        print(i)
        
    print(list(my_range(0, 1, 0.15)))
    
    0
    0.25
    0.5
    0.75
    
    [0, 0.15, 0.3, 0.44999999999999996, 0.6, 0.75, 0.9]
    

    反正我个人是越来越喜欢用生成器了, 尤其在写函数的时候, 优先考虑用 yield 而不是 return , 其好处在于更加优雅, 同时节省内存, 且后面还可以运行代码, 简直大爱. 一个函数中, 如果出现 yield 语句, 则将其转为了生成器. 跟普通函数不同在于, 生成器只能用于迭代操作, 不会终止函数, 而 return 则彻底结束函数运行.

    def count_down(n):
        print('Start to count from', n)
        while n > 0:
            yield n 
            n -= 1
        print('Done!')
        
    # test 
    c = count_down(3)
    
    print(c)
    
    print(next(c))
    print(next(c))
    print(c.__next__())
    print(next(c))
    
    <generator object count_down at 0x000002070EE99DB0>
    Start to count from 3
    3
    2
    1
    Done!
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-28-865f6082c7dc> in <module>
         14 print(next(c))
         15 print(next(c))
    ---> 16 print(next(c))
    
    StopIteration: 
    
    

    一个生成器函数的主要特征是它会回应在迭代中使用到的 next 或者, 一旦生成器返回退出, 则迭代终止. 通常的做法是用 用 for 去进行迭代, 不会出现报错的细节呢.

    因为, for 的原理, 是一个迭代器的工作过程, 判断是否可迭代, 然后调用 __ next __ 不断取数, 直到异常 StopIteration.

    小结

    • 复习了一把迭代, 可迭代对象, 迭代器, 集合对象, 序列对象, 容器等基础概念
    • 迭代的原理, 即是实现了 __ iter __ 和 __ next __ () 方法, 即将返回自身可迭代对象和, 返回当前值并指向下next 节点
    • 函数中用 yield 是真的香, 结合 for 遍历的原理, 不断调用 __ next__ 和 捕捉 StopIteration 异常
  • 相关阅读:
    C#多线程编程实战(二)
    C#为什么要多线程开发(一)
    海康威视实时预览回调PS流用EasyRTMP向RTMP服务器推流中视频数据处理的代码
    CentOS "libc.so.6: version 'GLIBC_2.14' not found"解决方法,同理'GLIBC_2.15' not found"
    EasyRTMP结合海康HCNetSDK获取海康摄像机H.264实时流并转化成为RTMP直播推流(附源码)
    基于EasyDSS流媒体解决方案创建视频点播、短视频、视频资源库等视频播放系统
    EasyNVR是怎么做到Web浏览器播放RTSP摄像机直播视频延时控制在一秒内的
    EasyNVR depends on ffmpeg,yasm/nasm not found or too old. Use --disable-yasm for a crippledbuild
    EasyDSS流媒体服务器软件支持HTTPS-启用https服务申请免费证书
    EasyDSS流媒体服务器软件(支持RTMP/HLS/HTTP-FLV/视频点播/视频直播)-正式环境安装部署攻略
  • 原文地址:https://www.cnblogs.com/chenjieyouge/p/13121317.html
Copyright © 2011-2022 走看看