• day 关于生成器的函数


    def average():
    count=0
    toatal=0
    average=0
    while True:
    value=yield average
    toatal+=value
    count+=1
    average=toatal/count
    g=average()
    print(g.__next__()) #激活了生成器,调用函数后 从头开始到 返回average 返回yield后面的average,为0
    print(g.send(10)) #把10传递给yield前的value,继续执行后面的代码,value = 10 total= 10+0 count =1+0 average= 10/1 = 10
    print(g.send(20)) #把20传递给yield前的value,继续执行后面的代码,value = 20 total= 10+20 count =1+1 average= 30/2 =15
    print(g.send(30))                             #把30传递给yield前的value,继续执行后面的代码,value = 30 total= 30+30  count =1+1+1  average= 90/3 =30 

    print(g.send(40))
    print(g.send(50))


    一、迭代器(dir()可以查函数具有什么键的功能)

    1、可迭代的——iterable(字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。)

    可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法。

    (1)判断是否可迭代的方法:

    from collections import Iterable
    print(isinstance('aaa',Iterable)                       #输出结果:True
    print(isinstance(123,Iterable)                         #输出结果:False
    print(isinstance([1,2,3],Iterable)                    #输出结果:True
     print('__iter__' in dir([1,2,3,4])) # True    可迭代的

    (2)可迭代协议

      包含‘__iter__'方法的数据类型就是可迭代的。输出数据类型所有方法的方式如下:

    #实例:求出两个不同数据类型的方法的不同
    difference=set(dir([1,2,3]))-set(dir(123))          #dir()方法以列表形式列出数据的所有的方法
    print(diffenrence)

    2、迭代器——iterator

    (1)判断迭代器的方法(迭代器 : __iter__ 和__next__)

    from collection import Iterator
    iterator_lst=[1,2,3].__iter__()
    print(isinstance(itertor_lst,Iterator)               #输出结果为:True
    print(isinstance([1,2,3],Iterator)                   #输出结果为:False
    print('__next__' in dir([1,2,3,4])) # False

    (2)迭代器协议

      迭代器中有'__next__'和'__iter__'方法

    (3)常见迭代器

      a.先天的:文件句柄;b后天的:从可迭代对象转变,格式为:“可迭代对象.__iter__()”

    (4)迭代器取值

    lst_iterator=[1,2,3].__iter__()  先有iter
    print(lst_iterator.__next__())   才能取值              #输出结果为:1
    print(lst_iterator.__next__())                        #输出结果为:2
    print(lst_iterator.__next__())                        #输出结果为:3
    #超过迭代器中的内容就会报错:stopIterator

    (5)优点(迭代器是个好东西)

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

    3、二者的区别

    (1)可迭代对象包含迭代器;(2)迭代器=可迭代对象.__iter__();(3)可以对可迭代对象和迭代器进行循环

    二、生成器

    1、定义:生成器就是迭代器,生成器是我们自己写出来的

    2、生成器函数:带有关键字yield/yield from的函数就称为生成器函数

    (1)生成器函数在执行时候只返回一个生成器,不执行生成器函数中的内容

    (2)从生成器中取值

      a.生成器.__next__():生成器函数中有几个yield,就可以取几次

    复制代码
    def generator():
        print(123)
        yield 'aaa'
        print(456)
        yield 'bbb'
    g=generator()
    print(g.__next__())  # 123 aaa
    print(g.__next__())  # 456 bbb
    def list():
    print(123)
    yield 'aaa'
    print(456)
    yield 'bbb'
    print(list().__next__()) # 123 aaa
    print(list().__next__()) # 123 aaa
     注意:前者为创建一个生成器,后者为每次重新创建一个生成器
    复制代码

    b、for 循环取值

    复制代码
    def func():
        print(123)
        yield 'aaa'
        print(456)
        yield 'bbb'
    g=func()
    for i in g:
        print(i)
    123
    aaa
    456
    bbb
    复制代码
    3、用while循环模拟for循环的方式 —— for循环是依赖迭代器的,且我们自己也可以仿照着写
    复制代码
    l = [1,2,3,4,5]
    l_iter = l.__iter__()  定义
    while True:
        try:
            print(l_iter.__next__())
        except StopIteration: # 异常处理机制
            break
    复制代码

    实例、

    复制代码
    def cloth():
        for i in range(10000):
            yield '衣服%s'%i
    
    g = cloth()
    for i in range(50):
        print(g.__next__())
    
    for i in range(50):
        print(g.__next__())
    复制代码

       list(生成器函数) 返回一个列表,里面装着生成器中的所有内容

    def generator():
        yield 'aaa'
        yield 'bbb'
    g=generator()
    print(list(g))       # [aaa,bbb]

    实例

    1、监听器例子

    复制代码
    监听器
    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())
    生成器监听文件输入的例子
    复制代码

    2、计算移动平均值

    复制代码
    def averger():
        total = 0.0
        count = 0
        average = None
        while True:
            term = yield average
            total += term
            count += 1
            average = total/count
    
    g_avg = averger()
    next(g_avg)
    print(g_avg.send(10))
    print(g_avg.send(100))
    print(g_avg.send(20))
    print(g_avg.send(30))
    复制代码

    三、重要会

    复制代码
    def g_func():
     print('aaaaa') # aaaaa
     yield 1 # 返回值 每次只占用一次内存,用完就没了
     print('bbbbb') #bbbbb
     yield 2 # 返回值
     yield 3 # 返回值
     # return [1,2,3] #直接return 是列表,当列表数大的时候会比较占用内存
     # for i in range(20000): #当数量较大时,生成器函数可以这样写、
     # yield i
    g = g_func()
    # for i in g:
    # print(i)
     
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    复制代码
    复制代码
    def cloth():
     for i in range(10000):
     yield '衣服%s'%i
     
    g = cloth()
    for i in range(50):
     print(g.__next__())
     
    for i in range(50):
     print(g.__next__())
    复制代码

    一、生成器中的send用法

      send可以把一个值作为信号量传递到生成器函数中,然后和__next__方法一样获取生成器中的值;在生成器执行伊始,只能先使用__next__;二者都是终于yield,而send需要始于一个未被返还的yield处,否则传递的数值将无法被接收。

    1、求重复累加平均实例

    复制代码
    def average():
        count=0
        toatal=0
        average=0
        while True:
            value=yield average
            toatal+=value
            count+=1
            average=toatal/count
    g=average()
    print(g.__next__())                           #激活了生成器,返回yield后面的average,为0
    print(g.send(10))                             #把10传递给yield前的value,继续执行后面的代码,终于yield后面的average,返回10
    print(g.send(20))                             #把20传递给yield前的value,继续执行后面的代码,终于yield后面的average,返回15
    print(g.send(30))                             #..........
    print(g.send(40))
    print(g.send(50))
    复制代码

    2、用send传值失败实例

    复制代码
    def func():
        print(1)
        yield 2
        print(3)
        value = yield 4
        print(5)
        yield value
    
    g = func()
    print(g.__next__())                          #打印出1和返回2,然后在第一个yield处停止等待
    print(g.send(88))                            #由于第一个yield处没有未被返回的值,故send传值失败,打印出3和返回4,在第二个yield处停止等待
    print(g.__next__())                          #value无值传入,打印出5后在第3个yield处返回none
    复制代码

    3、用next激活生成器计算累加平均值

    复制代码
    def init(func):                              #在调用被装饰生成器函数的时候首先用next激活生成器
        def inner(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return inner
    @init
    def average():
        mount=0
        total=0
        average=0
        while True:
            value=yield average
            total+=value
            average=total/mount
    g_avg=average()
                                                # next(g_avg)   在装饰器中执行了next方法
    print(g_avg.send(10))
    print(g_avg.send(20))
    print(g_avg.send(30))
    复制代码

    二、列表表达式和生成器表达式

    1、列表表达式

      简化代码,返回的必须是一个列表

    复制代码
    #普通代码
    result=[]
    for i in [1,2,3]
        result.append[i*i]
    print(result)
    
    #列表表达式
    print([i*i for i in [1,2,3]])
    复制代码

    (1)30内能被3整除的数的实例

    print([i for i in range(1,31) if i%3==0])

    (2)找到嵌套列表中有两个‘e’的名字

    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    print([for list in names for name in list if name.count('e')==2])

    2、生成器表达式

      把列表解析的[]换成()得到的就是生成器表达式;列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

    复制代码
    laomuji=('鸡蛋%s' %i for i in range(10))        #生成器表达式
    print(laomuji)                                 #返回生成器地址<generator object <genexpr> at 0x000001E17AF23BA0>
    print(next(laomuji))                           #输出结果为:鸡蛋0
    print(laomuji.__next__())                      #输出结果为:鸡蛋1
    print(next(laomuji))                           #输出结果为:鸡蛋2
                                                   #next(laomuji)等价于laomuji.__next__()
    复制代码

    3、字典推导式

    #将字典键与值对调
    mcase = {'a': 10, 'b': 34}
    print({mcase[k]:k for k in mcase})

    4、集合推导式

      自带去重功能,将列表解析式的[]换成{}得到集合推导式

    print({i*i for i in [1,-1,2]})    #结果为{1,4}

    1.把列表解析的[]换成()得到的就是生成器表达式

    2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

    3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:

    sum(x ** 2 for x in range(4))

    而不用多此一举的先构造一个列表:

    sum([x ** 2 for x in range(4)]) 

    生成器面试题

    复制代码
    def demo():
        for i in range(4):
            yield i
    
    g=demo()   # 生成器
    
    g1=(i for i in g) #生成器
    g2=(i for i in g1) #g2 生成器
    
    # print(list(g1))   #[0,1,2,3]
    print(list(g2))
    复制代码
    复制代码
    def add(n,i):
        return n+i
    
    def tes():
        for i in range(4):
            yield i
    
    g=tes()
    for n in [1,5,10]:
        g=(add(n,i) for i in g)
    n=1
    g=(add(n,i) for i in tes())  #--->  g=(add(n,i) for i in g) 生成器,没要,不会给值   -->tes() = g
    n = 5
    g=(add(n,i) for i in (add(n,i) for i in tes()))
    n = 10
    g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in tes())))
    # g=(30,31,32,33)
    print(list(g))
  • 相关阅读:
    [转]protobuf的编译安装
    [转]OpenMP中几个容易混淆的函数(线程数量/线程ID/线程最大数)以及并行区域线程数量的确定
    C++类中静态数据成员MAP如何初始化
    [转]gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 参数详解
    的机器学习开源工具分享
    机器学习常见的采样方法
    图像配准与深度学习方法
    卷积网络中的几何学你了解多少?
    云计算、虚拟化和容器
    在数据科学领域,你掌握这个24个python库就够了!
  • 原文地址:https://www.cnblogs.com/xiaoluoboer/p/7989588.html
Copyright © 2020-2023  润新知