1. 程式人生 > >13 生成器函數

13 生成器函數

key generator 索引 name 學員 一道 們的 傳值 ===

主要內容:

1. 生成器:生成器的實質就是叠代器,在python中有三種方式可以獲取生成器:

  通過生成器函數

  通過各種推導式來實現生成器

  通過數據的轉換也可以實現生成器

2. 生成器函數

  a: 函數中包含了yield的就是生成器函數.

   註意:生成器函數被執行,獲取的是生成器,而不是函數的執行

def fn():
    print("張傑")
    yield "謝娜"    #函數中包含yeild說明該函數不是一個普通的函數,而是生成器函數
    print("你好啊")
    yield "hi"
    print("明日之子")
    yield ‘pick田四火‘
s = fn()       #創建一個生成器
print(s.__next__())
print(s.__next__())
print(s.__next__())      #最後一個yield執行完畢,在執行yield會報錯.
#return 直接返回函數結果,結束調用
#yeild 返回結果,可以讓函數分段進行

  b: 註意

def func():
    print("張傑")
    yield "謝娜"    #函數中包含yeild說明該函數不是一個普通的函數,而是生成器函數
    print("明日之子")
    yield ‘pick田四火‘
g1 = func()                  #表示兩個相同的生成器,第一個從頭開始指向下一個元素,第二個也是從頭開始指向元素.
g2 = func()
print(g1.__next__())        #張傑謝娜
print(g1.__next__())        #明日之子,田四火
print("==============")
print(g2.__next__())        #張傑謝娜

  c: 生成器的優點,可以節約內存,

  例題:例如老男孩教育要給每個培訓的學員定制一套衣服,共10000套.

def fn():
    lst = []
    for i in range(1,10001):
        lst.append(‘衣服%s‘ % i)
    return lst
s = fn()
print(s)

  缺點:一次性全部拿出來,會很占用內存.

def fn():
    lst = []
    i = 1
    while i < 100001:
        yield ‘衣服%s‘ % i
        i = i + 1
g = fn()
print(g.__next__())
print(g.__next__())
print(g.__next__())

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

  d: 拿到的是生成器. 生成器的本質是叠代器. 叠代器可以被叠代 生成器可以直接for循環

def func():
    yield 11
    yield 22
    yield 33
g = func()    #拿到的是生成器,生成器的本質是叠代器,叠代器可以被叠代,生成器可以直接for循環
for i in g:
    print(i)

  e: list[g]

def func():
    yield 11
    yield 12
    yield 13
    yield 14
g = func()           #獲取生成器
lst = list(g)        #括號裏必須為可叠代對象
print(lst)

3. send: send和__next__一樣,都可以讓生成器執行到下一個yield.

  send和__next__的區別:

    send():也可以讓生成器向下執行一次,給上一個yield傳一個值,第一個不能用send,最後一個也不要傳值.

    __next__:可以使生成器向下執行一次.

def eat():
    print("我吃什麽啊")
    a =  yield  "饅頭"
    print("a=",a)
    b =  yield  "大餅"
    print("b=",b)
    c =  yield  "韭菜盒子"
    print("c=",c)
    yield  "GAME OVER"
gen = eat()      # 獲取?成器
print(gen. __next__ ())      #到yield結束,返回饅頭
print(gen.send("胡辣湯"))    #可以給上一個yield傳值,a = 胡辣湯
print(gen.send("狗糧"))      #可以給上一個yield傳值,b = 狗糧
print(gen.send("貓糧"))      #可以給上一個yield傳值,c = 貓糧

4. 列表推導式

語法:[最終結果 for 變量 in 可叠代對象 ]

語法:[最終結果 for 變量 in 可叠代對象 if 條件]

  生成列表,裏面裝1-14數據

    普通模式

li = []
for i in range(1,15):
    li.append(‘python%s期‘ % i)
print(li)

    采用推導式

li = [‘python%s期‘ % i for i  in range(1,15)]
print(li)
# [‘python1期‘, ‘python2期‘, ‘python3期‘, ‘python4期‘, ‘python5期‘, ‘python6期‘, ‘python7期‘, ‘python8期‘, ‘python9期‘, ‘python10期‘, ‘python11期‘, ‘python12期‘, ‘python13期‘, ‘python14期‘]

  獲取100以內能被3整除的數的平方

li = [i*i for i in range(101) if i % 3 == 0 ]
print(li)

  尋找名字中帶有兩個e的人的名字

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

5. 字典推導式

  dic = {"a":"b", "c":"d"},把字典中的key和value互換:

dic = {‘a‘:‘b‘,‘c‘:‘d‘}
new_dic = { dic[key]:key for key in dic}
print(new_dic)

  lst1作為key,lst2作為value

lst1 = ["alex", "wusir", "taibai", "ritian"]
lst2 = [‘sb‘, "很色", "很白", "很牛"]
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}      #取他們的索引
print(dic)

6. 集合推導式

lst = [‘馬化騰‘,‘馬化騰‘,‘王建中‘,‘張建忠‘,‘張雪峰‘,‘張雪峰‘]
s = {i for i in lst}
print(s)

7. 生成器表達式

  把列表推導式[]變成(),就成為生成器表達式

  格式(最終結果 for 變量 in 可叠代對象)

gen = ("麻花藤我第%s次愛你" % i for i in range(10))
print(gen)                #<generator object <genexpr> at 0x0000021314580F68>

  打印的結果是一個生成器,我們可以用for循環來循環這個生成器.

gen = ("麻花藤我第%s次愛你" % i for i in range(10))
for i in gen:
    print(i)

  生成器表達式也可以進行篩選:

gen = (i for i in range(100) if i % 3 == 0)
for e in gen:
    print(e)

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

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

  b: 得到的值不一樣,列表推導式得到的是一個列表,生成器表達式獲取的是一個生成器.

  形象的說明:列表推導式:直接拿到一筐子雞蛋,生成器表達式:拿到一個老母雞,需要的時候母雞就給你下雞蛋.

  生成器的惰性機制:

    生成器只有在訪問的時候才取值,說白了,你找他要,他才給你,不找他要,他不會執行.

# 生成器的惰性機制:
def func():
    print(111)
    yield 222
g = func()             #通過生成器函數獲得的生成器
g1 = (i for i in g)   #通過生成器表達式獲得的生成器g1
g2 = (i for i in g1)  #生成器g2
print(list(g))     #獲取g中的數據,這是func()才會執行,打印111,獲取到222,g完畢.
print(list(g1))    #獲取g1中的數據,g1 的數據來源g,但是g已經取完了,g1也就沒有數據了.
print(list(g2))

  有關生成器表達式的惰性機制的一道面試題

def add(a, b):
    return a + b
def gen():
    for r_i in range(4):
         yield r_i
g = gen()
for n in [2, 10]:
    g = (add(n, i) for i in g)  #生成器的惰性機制,生成器只有在訪問的時候才取值,說白了,你找他要,他才給你值.不找他要不會給你的
print(list(g))                   #不到最後不會拿值:惰性機制.

  

def add(a, b):
    return a + b
def test():
    for r_i in range(4):
         yield r_i
# g = test()
    # g = (add(n, i) for i in g)  #生成器的惰性機制,生成器只有在訪問的時候才取值,說白了,你找他要,他才給你值.不找他要不會給你的
    g = (add(10, i) for i in (add(10, i) for i in 0,1,2,3)  #第二次執行的時候替換後面的g
    g = (add(10, i) for i in 10,11,12,13
print(list(g))
# lst(g) = [20,21,22,23]

  

  

  

13 生成器函數