python之生成器(~函數,列表推導式,生成器表達式)

一.生成器python

概念:生成器的是實質就是迭代器面試

1.生成器的貼點和迭代器同樣,取值方式也和迭代器同樣.app

2.生成器通常由生成器函數或者聲稱其表達式來建立,生成器其實就是手寫的迭代器.函數

3.在python中有三種方式來獲取生成器:spa

  (1)經過生成器函數獲取生成器指針

  (2)經過各類推導式來實現生成器;code

  (3)經過生成器表達式來建立生成器對象

 

二.生成器函數blog

  首先,先看一個簡單函數,以下:內存

def jaun():
        print("111")
        return 222

    ret = juan()
    print(ret)
    # 結果爲:
    # 111
    # 222

  將上面函數中的return換成yield就是生成器,以下:

def juan():
        print("111")
        yield 222

    ret = juan()
    print(ret)
    # 結果爲:<generator object func at 0x0000000002793CA8>

  因爲函數中存在了yield,那麼這個函數就是一個生成器函數.這時,再執行這個函數的時候,就再也不在是函數的執行了,而是獲取這個生成器.

  生成器的本質是迭代器,因此,咱們能夠直接執行__next__()來執行一下生成器

def juan():
    print("111")
    yield 222

enner = juan()  #這個時候函數不會執行,而是獲取到生成器
ret = genner.__next__()  #這個時候纔會執行,yield的做用和return同樣,也是返回數據
print(ret)

    # 結果爲:
    # 111
    # 222

yield 和 return的區別:

      yield是分段來執行一個函數,return是直接中止執行函數

  

  當程序運行完最後一個yield,那麼後面繼續進行__next__()程序會報錯,具體以下

def juan():
    print("111")
    yield 222
    print("222")
    yield 444

gener = func()
ret = gener.__next__()
print(ret)
ret2=gener.__next__()
print(ret2)
ret3=gener.__next__()
print(ret3)

# 結果爲:
    # 111
    # Traceback (most recent call last):
    # 222
    #   File "E:/pythonDemo/1-basis/test13.py", line 50, in <module>
    # 222
    # 444
    #     ret3 = gener.__next__()
    # StopIteration

講到這裏.那生成器有什麼做用呢?咱們來看這樣一個需求,學校向JACK JONES訂購10000套學生服,JACK JONES就比較實在,直接造出來10000套衣服,以下代碼:

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

可是呢,問題來了,學校如今沒有這麼多學生,一次性給學校這麼多,該往哪裏放,很尷尬啊!最好的效果是什麼樣呢?我要1套,你給我1套,一共10000套,是否是最完美的。以下代碼:

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

  分析:第一種是直接一次性所有拿出來,會很佔用內存,第二種是使用生成器,一次就一個,

用多少生成多少,生成器是一個一個的指向下一個,不會回去,__next__()到哪,指針就指到哪兒,下一次繼續去指針指向的值.


接下來咱們來看send()方法,send和__next__()同樣均可以讓生成器執行到下一個yield,以下代碼:

def eat():
        print("我吃什麼啊")
        a = yield "饅頭"
        print("a=",a)
        b = yield "大餅"
        print("b=",b)
        c = yield "韭菜盒子"
        print("c=",c)
        yield "GAME OVER"

    gen = eat()  # 獲取生成器
    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發送值,在第一次執行生成器代碼的時候不能使用send()。

 

生成器能夠使用for循環來循環獲取內部的元素:

def func():
        print(111)
        yield 222
        print(333)
        yield 444
        print(555)
        yield 666
    
    gen = func()
    for i in gen:
        print(i)
    # 結果爲:
    # 111
    # 222
    # 333
    # 444
    # 555
    # 666

三,推導式、生成器表達式

       首先咱們先看一下這樣的代碼,給出一個列表,經過循環,向列表中添加1-13:,代碼以下:

    lst = []
    for i in range(1,14):
        lst.append(i)
    print(lst)

  將上面替換成列表推導式,以下:

    lst = [i for i in range(1,14)]
    print(lst)

  列表推導式是經過一行來構建你要的列表,列表推導式看起來代碼簡單,可是出現錯誤以後很難排查。

列表推導式的經常使用寫法:[結果 for 變量 in 可迭代對象]

例:從python1期到python15期寫入列表lst,代碼以下:

 lst = ["python%s" % i for i in range(1,16)]
 print(lst)

咱們還能夠對列表中的數據進行篩選:篩選模式:[結果 for 變量 in 可迭代對象 if條件],具體以下例:

 # 獲取1-100內全部偶數
    lst = [i for i in range(1,101) if i % 2 == 0]
    print(lst

生成器表達式和列表推導式的語法基本上是同樣的,只是把[]替換成(),具體以下:

gen = (i for i in range(10))
print(gen)   # 結果爲:<generator object <genexpr> at 0x00000000021F3E60>

能夠看到打印的結果就是一個生成器,咱們能夠使用for循環來循環這個生成器,具體以下:

gen = ("數碼寶貝我第%s次愛你" % i for i in range(10))
 for i in gen:
     print(i)

生成器表達式也能夠進行篩選,具體以下:

# 獲取1-100內能被3整除的數
    gen = (i for i in range(1,100) if i % 3 == 0)
    for num in gen:
        print(num)

    # 100之內能被3整除的數的平方
    gen = (i * i for i in range(100) if i % 3 == 0)
    for num in gen:
        print(num)

    # 尋找名字中帶有兩個e的人的名字
    names = [
        ['Tom','Billy','Jefferson','Andrew','Wesley','Steven'],
        ['Alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']
    ]

    # 不用推導式和表達式
    result = []
    for first in names:
        for name in first:
            if name.count("e") == 2:
                result.append(name)
    print(result)

    # 生成器表達式
    gen = (name for first in names for name in first if name.count("e") == 2)
    for name in gen:
        print(name)

總結:

       生成器表達式和列表推導式的區別:

       1,列表推導式比較耗內存,一次性加載,生成器表達式幾乎不佔用內存,使用的時候才分配和使用內存;

       2,獲得的值不同,列表推導式獲得的是一個列表,生成器表達式獲取的是一個生成器;

舉個栗子:一樣一籃子雞蛋,列表推導式:直接拿到一籃子雞蛋;生成器表達式:拿到一個老母雞,須要雞蛋就給你下雞蛋。

生成器的惰性機制:生成器只有在訪問的時候才取值,說白了,你找他要他纔給你值,不找他要,他是不會執行的。

def func():
        print(111)
        yield 222

    g = func()  # 生成器g
    g1 = (i for i in g)  # 生成器g1,可是g1的數據來源於g
    g2 = (i for i in g1)  # 生成器g2,數據來源於g1

    print(list(g))  # 獲取g中的數據,這是func()纔會被執行,打印111,獲取到222,g完畢
    print(list(g1)) # 獲取g1中的數據,g1的數據來源是g,可是g已經取完了,g1也就沒有數據了
    print(list(g2)) # 和g1同理

深坑:生成器,要值的時候纔拿值!

字典推導式:根據名字應該也能猜到,推導出來的是字典,具體以下:

# 把字典中的key和value互換
    dic = {'a':1,"b":2}
    new_dic = {v:k for k,v in dic.items()}
    print(new_dic)

    # 在如下list中,從lst1中獲取的數據和lst2中相對應的位置的數據組成一個新字典
    lst1 = ['jay','jj','sylar']
    lst2 = ['周杰倫','林俊杰','邱彥濤']
    dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
    print(dic)

集合推導式:集合推導式能夠幫咱們直接生成一個集合,集合有無序,不重複的特色,因此集合推導式自帶去重功能。具體以下代碼:

   lst = [1,-1,8,-8,12]
    # 絕對值去重
    s = {abs(i) for i in lst}
    print(s)

總結:

  推導式有:

    列表推導式:[結果 for 變量 in 可迭代對象 if 條件篩選]

    字典推導式:{k:v for 變量 in 可迭代對象 if 條件篩選}

    集合推導式:{k for 變量 in 可迭代對象 if 條件篩選}

    沒有元組推導式

    生成器表達式: (結果 for 變量 in 可迭代對象 if 條件篩選)

         生成器表達式能夠直接獲取到生成器對象,生成器對象能夠直接進行for循環,生成器具備惰性機制。

 

看下面一個面試題(難度係數50000000顆星,友情提示:惰性機制,不到最後不會拿值):

def add(a,b):
        return a+b

    def test():
        for r_i in range(4):
        yield r_i

    g = test()

    for n in [2,10]:
    g = (add(n,i) for i in g)

#過程
#1)
#n=2
#g1 = (add(n,i) for i in g)

#n=10
#g = (add(n,i) for i in g1)
----------------------------
#2)
#g = (add(n,i) for i in add(n,i) for i in g)
----------------------------------------
#3)

#g = (add(10,i) for i in add(10,i) for i in g)
 [10,11,12,13]
結果:[20,21,22,23]



print(list(g))
相關文章
相關標籤/搜索