zoukankan      html  css  js  c++  java
  • 同学,迭代器生成器了解一下

    迭代器

    可迭代的

    一个含有__iter__方法的对象就是可迭代的,他们都可以使用for循环取值(这样说并不对,__iter__方法应返回一个迭代器).

    例如:

    print('__iter__' in dir([])) # True
    print('__iter__' in dir(())) # True
    print('__iter__' in dir("wfdsf")) # True
    print('__iter__' in dir(123)) # False

    迭代器

    内部含有__next__方法的可迭代对象就是迭代器 , 迭代器是可迭代的一部分.

    可迭代对象调用__iter__()就形成了一个迭代器

    ret = "adc".__iter__()
    ret2 = ret.__iter__()
    # 查看类型
    print(type(ret)) # <class 'str_iterator'>
    # 查看可迭代对象与迭代器之间的差集
    print(set(dir("abc".__iter__()))-set(dir("abc")))
    # {'__next__', '__setstate__', '__length_hint__'}
    # 查看迭代器与可迭代对象的__iter__方法有什么不同
    print(ret==ret2) # True
    # 使用__next__方法从迭代器中取值
    print(ret.__next__()) # a
    print(ret.__next__()) # b
    print(ret.__next__()) # c
    print(ret.__next__()) # 抛出 StopIteration 异常
    
    #利用while循环来实现for循环的功能
    l = [1,2,3,4]
    l_iter = l.__iter__()
    while True:
        try:        #处理异常
            item = l_iter.__next__()
            print(item)
        except StopIteration:
            break
    

    判断一个对象是不是迭代器或一个可迭代的

    方式一,

    判断方法__iter__是否存在于变量的方法中,存在则是可迭代的(除非你自己写了个类实现了此方法)

    判断方法__next__是否存在于变量的方法中,存在则是迭代器(除非你自己写了个类实现了此方法)

    print('__iter__' in dir([1,2,3,4])) # True
    print('__next__' in dir([1,2,3,4])) # False

     方式二

    判断对象是不是迭代器或可迭代对象的实例

    from collections import Iterable # 可迭代对象的类
    from collections import Iterator # 迭代器的类
    print(isinstance([1,2,3,4],Iterable)) # True
    
    str_iter = [1,2,3,4].__iter__()
    print(isinstance(str_iter,Iterator)) # True
    
    print(isinstance([1,2,3,4],Iterator)) # False
    

    迭代器的特点

    • 惰性运算
    • 从前到后一次取值,过程不可逆,不可重复
    • 节省内存

    生成器

    生成器的本质就是迭代器

    因此生成器具有迭代器的特点,但是生成器是我们自己写的代码

    生成器函数

    一个包含yield关键字的函数就是一个生成器函数。

    yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

    def genrator_fun1(): # 这个函数就是一个生成器函数
        yield 1
        yield 2
    x=genrator_fun1()#x 就是一个生成器
    print(type(x)) # <class 'generator'>
    print(x.__next__()) # 1
    print(x.__next__()) # 2
    

    监听文件末尾追加的例子:

    #监听文件末尾追加的例子
    def tail():
        f = open('文件','r',encoding='utf-8')#打开文件
        f.seek(0,2)把光标移至末尾
        while True:
            line = f.readline()#读取内容
            if line:#内容不为空
                yield line#返回读取到的内容
            import time
            time.sleep(0.1)
    g = tail()
    for i in g:
        print(i.strip())
    

    send方法

    send方法可以将数据传递给生成器,并返回了一个yield值

    def func():
        a = yield 5
        # send的值会由yield前的变量接收,因为表达式会先计算右边的值,后面不会执行
        # 所以说至少yield一次才能send,否则会抛出TypeError异常
        yield a
    
    g = func()
    num = g.__next__()
    print(num) # 5
    num2 = g.send('alex')
    print(num2) # alex
    

    第一次也可以g.send(None),相当于g.__next__()

    求平均数实例

    def init(func):  #生成器的预激装饰器
        def inner(*args,**kwargs):
            g = func(*args,**kwargs)   #func = averager
            g.__next__() # 先执行一次__next__()
            return g
        return inner
    
    @init
    def averager(): # 求平均值
        total = 0.0
        count = 0
        average = None
        while True:
            term = yield average # 返回average, send传值给term
            total += term # 总和
            count += 1 # 次数
            average = total/count # 平均数
    
    g_avg = averager()
    print(g_avg.send(10))#10
    print(g_avg.send(30))#20
    

    yield form用法

    def func():
        a = 'AB'
        b = 'CD'
        yield from a# 相当于for i in a:yield i
        yield from b# 相当于for i in b:yield i
    
    # 'A','B','C','D'
    # 返回了4次
    g = func()
    for i in g:
        print(i)
    

    生成器表达式

    #列表推导式
    y = [1,2,3,4,5,6,7,8]
    x = [1,4,9,16,25,36,49,64]
    #由列表y要得到一个列表x
    x = [i*i for i in y]#列表推导式
    
    
    #生成器表达式
    #把列表推导式的[]换成()就变成了生成器表达式。
    l = ['鸡蛋%s'%i for i in range(10)]
    print(l)#列表表达式获得一个列表
    #生成器表达式获得了一个生成器
    laomuji = ('鸡蛋%s'%i for i in range(10))
    for egg in laomuji:
        print(egg)
    

    面向对象中使用__iter__

    for循环的本质起始就是调用一个对象的__iter__()方法,获得一个迭代器,使用__next__()方法取值,并且做了异常处理,我们自己定义类时,也可以自己是实现__iter__()方法,这样我们的对象就可以被循环了.

    class For:
        def __init__(self,list):
            self.list = list
        def __iter__(self):
            for i in self.list:
                yield i
    
    l = For([1,2,3,4,5,6])
    for i in l:
        print(i)
    

      在form组件中就用到了这种方法,当我们循环form实例时,他的__iter__方法循环他的字段列表,并将值yield会来

  • 相关阅读:
    mysql安装前的系统准备工作(转)
    mysql多实例的配置(转)
    饼干怪兽和APT攻击
    Linux
    android application简要类(一)
    轨道sql谈话 dbms_monitor
    Android有关Volley使用(十)至Request和Reponse意识
    data URI scheme及其应用
    java在string和int相互转化
    ComponentName意思
  • 原文地址:https://www.cnblogs.com/wwg945/p/8977755.html
Copyright © 2011-2022 走看看