Python生成器/生成器函數/推導式/推導式函數

1. 生成器
  生成器的本質就是迭代器python

  在python中有三種⽅方式來獲取⽣生成器:app

    1. 經過生成器函數
    2. 經過各類推導式來實現⽣成器
    3. 經過數據的轉換也能夠獲取生成器函數

  生成器的特色和迭代器同樣.取值方式和迭代器同樣(__next__(), send(): 給上一個yield傳值).
  生成器通常由生成器函數或者生成器表達式來建立
  其實就是手寫的迭代器spa

2. 生成器函數
  和普通函數沒有區別. 裏面有yield的函數就是生成器函數.
  生成器函數在執行的時候. 默認不會執行函數體. 返回生成器
  經過生成器的__next__()分段執行這個函數.
  send() 給上一個yield傳值, 不能再開頭(沒有上一個yield), 最後一個yield也不能夠用send()code

⾸先, 咱們先看一個很簡單的函數:對象

def func():
    print("111")
    return 222
ret = func()
print(ret)
結果: 111 222

 

將函數中的return換成yield就是生成器blog

def func():
    print("111")
    yield 222
ret = func()
print(ret)
結果:
<generator object func at 0x10567ff68>

  運⾏的結果和上⾯不同. 爲何呢. 因爲函數中存在了yield. 那麼這個函數就是⼀個生成器 函數. 這個時候. 咱們再執行這個函數的時候. 就再也不是函數的執行了. ⽽是獲取這個生成器. 如何使用呢? 想迭代器. 生成器的本質是迭代器. 因此. 咱們能夠直接執⾏__next__()來執行內存

如下生成器:generator

def func():
    print("111")
yield 222
gener = func() # 這個時候函數不會執行. ⽽是獲取到生成器
ret = gener.__next__() # 這個時候函數纔會執行. yield的做用和return同樣. 也是返回數據
print(ret)
結果:
111
222

 

那麼咱們能夠看到, yield和return的效果是同樣的. 有什麼區別呢? yield是分段來執⾏行一個函數. return呢? 直接中止執⾏函數.it

def func(): print("111") yield 222
    print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最後⼀個yield執⾏完畢. 再次__next__()程序報錯, 也就是說. 和return⽆關了.
print(ret3) 結果: 111 Traceback (most recent call last): 222
333 File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in
<module>
444 ret3 = gener.__next__() # 最後一個yield執行完畢. 再次__next__()程序報錯, 也就是說. 和return⽆關了.
StopIteration

當程序運⾏完最後一個yield. 那麼後⾯繼續進行__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)

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

3. 推導式
  1. 列表推導式 [結果 for循環 條件篩選]\

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

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

替換成列列表推導式:

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

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

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

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

⽣成器表達式和列表推導式的語法基本上是同樣的. 只是把[]替換成()

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

⽣成器表達式也能夠進行篩選:

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

  2. 字典推導式 {k:v for循環 條件篩選}

# [11,22,33,44] => {0:11,1:22,2:33,3:44}
lst = [11,22,33,44] dic = {i:lst[i] for i in range(len(lst)) if i < 2} print(dic) # 語法:{k:v for循環 條件篩選}

  3. 集合推導式 {k for循環 條件}

 

# 集合推到式
lst = [1,1,4,6,7,7,4,2,2] s = {el for el in lst} print(s) s = set(lst) print(s)

 

4. 生成器表達式

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

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

  2. 獲得的值不⼀樣.列表推導式獲得的是一個列列表.⽣成器表達式獲取的是一個生成器.

  (結果 for循環 條件)
  特色:
    1. 惰性機制
    2. 只能向前
    3. 節省內存

相關文章
相關標籤/搜索