zoukankan      html  css  js  c++  java
  • python全栈开发 生成器 :生成器函数,推导式及生成器表达式

    python 全栈开发 

    1.生成器函数

    2.推导式

    3.生成器表达式

    一.生成器函数

    1.生成器:

    生成器的本质就是迭代器

    (1)生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), send(): 给上一个yield传值).

    (2)生成器一般由生成器函数或者生成器表达式来创建

    (3)其实就是手写的迭代器

    2.生成器函数:

    (1)和普通函数没有区别. 里面有yield的函数就是生成器函数.

    (2)生成器函数在执行的时候. 默认不会执行函数体. 返回生成器

    (3)通过生成器的__next__()分段执行这个函数.

    (4)send()给上一个yield传值,不能在开头(没有上一个yield),最后的yield后面不能用send()

    例:

    首先,我们先来看一个简单的函数:

    def func():
        print('111')
        return 222
    ret = func()
    print(ret)
    
    
    #  111
       222

    将函数中的return 换成yield 就是生成器.

    def func():
        print("111")
        yield 222
    ret = func()
    print(ret)
    
    结果:
    <generator object func at 0x10567ff68>   # 只能的到生成器的内存地址

    这个函数中带有yield 所以这个函数就成了生成器函数.生成器本质就是迭代器,所以我们可以执行__next__()来执行这个生成器.

    def func():
        print("111")
        yield 222
    gener = func() # 这个时候函数不会执行. 而是获取到生成器
    ret = gener.__next__() # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据print(ret)
    结果:
    111
    222

    yield 和 return 的效果是一样的,但是yield 是分段执行一个函数,而 return 是直接停止执行函数.   当函数执行到最后一个field的时候,如果继续执行__next__(),则函数程序会报错.

    def func():
        print('111')
        yield 222
        print('333')
        field 444
    gener = func() 这个时候函数不会执行,只会获取生成器.
    ret = gener.__next__()
    print(ret)
    ret = gener.__next__()
    print(ret)
    ret = gener.__next__()  #最后一个yield执行完毕,再次__next__()则会报错.也就是说,和return无关了.
    print(ret)

    例:

    老男孩向 JAKE JONCES 订购了 10000套学生衣服,JAKE JONCES也很爽快,直接开了三辆卡车送来10000套衣服.

    def cloth():
    lst = []
    for i in range(0,10000):
        lst.append('衣服' + str(i))
        return lst
    cl = cloth()

    那么,问题来了.老男孩现在没有10000个学生,而且又没有多余的地方来存放衣服.那怎么办那?最好的效果是我要一套,你就给我一套,给够10000套.就完美了.

    def cloth():
        for i in range(0,10000):
            yield '衣服' + str(i)
    cl = cloth()
    print(cl.__next__())
    print(cl.__next__())
    print(cl.__next__())
    print(cl.__next__())
    print(cl.__next__())

    so.来看看这两种的区别: 第一种是直接一次性全都拿出来,会很占内存. 第二种是使用生成器,一次取一个,用多少取多少,生成器指向下一个,不会倒退.__next__()到哪,指针就指向哪里.下一次继续获取指针指向的值.

    例:

    下面我们来看 send 的方法.send()和__next__()都可以让生成器执行下一个field,但是send()会给生一个field的位置传递一个值.

    def chi():
        print('我吃什么')
        a = yield('馒头')
        print("a=",a)
        b = yield('大饼')
        print("b = ",b)
        c = yield("盖浇饭")
        print("c =",c)
        yield "GAME OVER"
    gen = chi()   #获取生成器
    ret1 = gen.__next__()
    print(ret1)
    ret2 = gen.send('包子')
    print(ret2)
    ret3 = gen.send('水饺')
    print(ret3)
    ret4 = gen.send('火腿肠')
    print(ret4)
    
    #我吃什么
    馒头
    a= 包子
    大饼
    b =  水饺
    盖浇饭
    c = 火腿肠
    GAME OVER

    send()与 __next__()的区别:

    1.send()和__next__()都让生成器往下走一次

    2.send()给上一个yield传值,不能在开头(没有上一个yield),最后的yield后面不能用send()

    生成器可以使用for循环来循环获取内部的元素:

    def func():
        yield 1
        yield 13
        yield 26
        yield 88
        yield 46
        yield 100
    gen = func()
    for i in gen:
        print(i)
    
    #1
       13
       26
       88
       46
       100

    for i in func(): # for的内部一定有__next__()
    print(i)

    print(list(func())) # 内部都有__next__()

    二.推导式

    1.列表推导式  [结果   for循环   条件筛选]

    2.字典推导式  {k:v  for循环 条件筛选}

    3.集合推导式  {k  for循环 条件}

    列表的推导式:

    首先我们先看一下这样的代码, 给出一个列表, 通过循环, 向列表中添加1-13:

    lst = []
    for i in range(1,14):
        lst.appdend(i)
    print(lst)
    
    
    # [1,2,3,4,5,6,7,8,9,10,11,12,13]

    然后我们转换成推导式方式:

     lst = [i for i in range(1,14)] print(lst) #[1,2,3,4,5,6,7,8,9,10,11,12,13] 

    例:

    从python第一期写到第十五期:

    lst = ["python" + str(i) for i in range(1,16)]
    print(lst)
    
    #['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14', 'python15']

    我们还可以对列表里的数据进行筛选:

    例:   100以内的奇数:

     lis = [i for i in range(100) if i % 2 ==1] print(lis) 

      100以内能被3整除的数的平方:

     lis = [i*i for i in range(100) if i % 3 == 0] print(lis) 

      寻找名字中带有两个e的人的名字:

    names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,'Joe'],[ 'Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' ]]

    for循环:

    lst = []
    for line in names:
        for name in line:
            if name.count('e') == 2:
                print(name)
      
     #Jefferson
    Wesley
    Steven
    Jennifer

    推导式:

    lst = [name for line in names for name in line if type(name) == str and name.count("e") == 2]
    print(lst)
    
    
    #Jefferson
    Wesley
    Steven
    Jennifer

    字典的推导式:

    例:dic = {"jj":"林俊杰","jay":"周杰伦","ln":"刘能","zs":"赵四"}

     d = {v:k for k,v in dic.items()} print(d) #{'林俊杰': 'jj', '周杰伦': 'jay','刘能': 'ln', '赵四': 'zs'} 

    集合的推导式: 可去重复

    例:lst = [1, 1, 4, 6,7,4,2,2]

     s = {el for el in lst} print(s) #{1, 2, 4, 6, 7} 

    元组没有推导式.

    三.生成器表达式

    结构: (结果  for循环 条件 )

    特点:

      1.惰性机制

      2.只能向前

      3.节省内存(鸡蛋和老母鸡)

    生成器的表达式和列表推导式的语法基本上一致,只是把[]换成了()

    例;

     gen = (i for i in range(10)) print(gen) # <generator object <genexpr> at 0x106768f10> 

    tu = (i for i in range(10)) # 没有元组推导式.  这是生成器表达式
    print(tu) # 生成器
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())

    生成器的表达式也可以进行筛选

    例:   获取1-100内能被3整除的数

     gen = (i for i in range(100) if i% 3 == 0) for num in gen; print(num) 

    生成器表达式和列表表达式的区别: 

    1. 列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存.使用的时候才使用和分配内存

    2.得到的值不一样,列表推导式的到的是一个列表,生成器表达式获取的是一个生成器.

    举个例子:

    同样一篮子鸡蛋. 列表推导式: 直接拿到一篮子鸡蛋. 生成器表达式: 拿到一个老母鸡. 需要鸡蛋是就给你下鸡蛋.

    生成器的惰性机制:生成器只有在访问时才取值,说白了,你找他要他才给你,不找他要,他是不会执行的.

    def func():
        print(111)
        yield 222
        yield 333
    g = func() # 获取生成器
    g1 = (i  for i in  g) # 生成器
    g3 = func()
    g2 = (i  for i in  g3) # 生成器
    print(list(g)) # ??? [222,333] 源头. 从源头把数据拿走了
    print(list(g1)) # ??? [] 这里执行的时候. 源头已经没有数据
    print(list(g2)) # ??? [] 这里也没有值了
    
    '''
    111
    [222, 333]
    []
    111
    [222, 333]
    '''

    类型: 求和

    例:

    def add(a, b):
        return a  + b
    # 生成器函数 #  0-3
    def test():
        for r_i in range(4):
            yield  r_i
    # 0,1,2,3
    g = test() # 获取生成器
    for n in  [2, 10]:
        g = (add(n, i) for i in g)
    print(g)
    # 到最后往里面放数据就对了
    print(list(g))
    print(list(g))
    
    '''
    <generator object <genexpr> at 0x00000000027C10A0>
    [20, 21, 22, 23]
    []
    '''
  • 相关阅读:
    Android 中文 SDK (47) —— Filter
    Android 中文API (65) —— BluetoothClass[蓝牙]
    Android 中文 API——android.widget合集(中)(50篇)(chm格式)
    android 中文 api (72) —— BluetoothSocket[蓝牙]
    Android 中文API (61) —— ViewSwitcher
    Android API 中文 (51) —— ZoomButtonsController
    Android API 中文 (55) —— ListAdapter
    Android SDK 中文 (56) —— ViewFlipper
    什么是 COM编程技术?
    怎么打出全角的小写英文字母?
  • 原文地址:https://www.cnblogs.com/qq1426794755/p/9470297.html
Copyright © 2011-2022 走看看