python (生成器,生成推導式)

一. 生成器python

  生成器的實質就是迭代器, 在python中有三種方式得到生成器app

    1. 生成器函數函數

    2. 各類推導式實現生成器spa

    3. 數據轉換也能夠得到生成器code

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 0x0000025256283A40>

  以上兩段代碼執行的結果不同. 由於下面的代碼有yield,因此這個函數就是一個生成器函數.這個時候再執行這個函數,就不在是函數的執行了.而是獲取這個生成器.blog

  因此要想運行這個函數,就要執行__next__()函數來執行函數內存

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

#結果:
#     111
#     222

  能夠看到:return和yield執行的效果是同樣. 可是兩者是有區別的,yield是分段執行一個函數,return是直接中止執行函數pycharm

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
#222
#333
#444
#Traceback (most recent call last):
# File "D:/pycharm項目/week3/day3/函數生成器.py", line 103, in #<module>
#    ret3 = gener.__next__()  # 最後⼀一個yield執⾏行行完畢. 再次#__next__()程序報錯, 也就是 說. 和return⽆無關了了.
#StopIteration

  當程序運行完後⼀個yield. 那麼後面繼續進行__next__()程序會報錯. generator

  生成器做用:

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

#結果:
#['衣服0', '衣服1', '衣服2', '衣服3', '衣服4', '衣服5', '衣服6', '衣服7', '衣服8', '衣服9', '衣服10', '衣服11', '衣服12', '衣服13', '衣服14', '衣服15', '衣服16', '衣服17', '衣服18', '衣服19', '衣服20', '衣服21', '衣服22', '衣服23', '衣服24', '衣服25', '衣服26', '衣服27', '衣服28', '衣服29', '衣服30', '衣服31', '衣服32', '衣服33', '衣服34', '衣服35', '衣服36', '衣服37', '衣服38', '衣服39', '衣服40', '衣服41', '衣服42', '衣服43', '衣服44', '衣服45', '衣服46', '衣服47', '衣服48', '衣服49', '衣服50', '衣服51', '衣服52', '衣服53', '衣服54', '衣服55', '衣服56', '衣服57', '衣服58', '衣服59', '衣服60', '衣服61', '衣服62', '衣服63', '衣服64', '衣服65', '衣服66', '衣服67', '衣服68', '衣服69', '衣服70', '衣服71', '衣服72', '衣服73', '衣服74', '衣服75', '衣服76', '衣服77', '衣服78', '衣服79', '衣服80', '衣服81', '衣服82', '衣服83', '衣服84', '衣服85', '衣服86', '衣服87', '衣服88', '衣服89', '衣服90', '衣服91', '衣服92', '衣服93', '衣服94', '衣服95', '衣服96', '衣服97', '衣服98', '衣服99']



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__())

#結果:
#    衣服0
#    衣服1
#    衣服2
#    衣服3

  區別: 第一種是將循環的內容直接所有拿出來,很佔用內存. 第二種使用生成器,一個__next__函數只拿出一個,以後循環中止在當前位置,下一個再取值再從中止位置繼續向前取值.

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

 

二. 列表推導式

  列表推導式:最終給的是列表

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

lst = []
for i in range(1,15):
    lst.append("python%s" % i)
print(lst)
#結果:
#['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']


lst = ["python%s" % i for i in range(1,15)]  
print(lst)              
#結果:
#['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']

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

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

g = (i for i in range(10))
print(g)    #打印結果是一個生成器
#結果:
#<generator object <genexpr> at 0x0000029147073A40>


gen = ("麻xx我第%s次愛你" % i for i in  range(10))
for i in  gen:    #遍歷生成器內容
    print(i)
#結果:
#麻xx我第0次愛你
#麻xx我第1次愛你
#麻xx我第2次愛你
#麻xx我第3次愛你
#麻xx我第4次愛你
#麻xx我第5次愛你
#麻xx我第6次愛你
#麻xx我第7次愛你
#麻xx我第8次愛你
#麻xx我第9次愛你      

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

lst = [i for i in range(1,101) if i % 3 == 0]
print(lst)
#結果:
#[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]

lst = [i*i for i in range(1,100) if i % 3 ==0]
print(lst)
#結果:
#[9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304, 2601, 2916, 3249, 3600, 3969, 4356, 4761, 5184, 5625, 6084, 6561, 7056, 7569, 8100, 8649, 9216, 9801]

找出下列名字中帶有兩個'e'的.
names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,
'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']]
lst = [ii for i in names for ii in i if ii.count('e') ==2]
print(lst)
#結果:
#['Jefferson', 'Wesley', 'Steven', 'Jennifer']

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

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

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

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

  總結:

    推導式有列表推導式,字典推導式,集合推導式,沒有元組推導式

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

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

相關文章
相關標籤/搜索