1. 程式人生 > >Python全棧(第一期)Day14

Python全棧(第一期)Day14

今日主要內容:
生成器函式進階
生成器表示式
列表推導式+字典推導式

一,知識點複習

1,迭代器

迭代器和生成器
迭代器:
雙下方法 : 很少直接呼叫的方法。一般情況下,是通過其他語法觸發的
可迭代的 —— 可迭代協議 含有__iter__的方法('__iter__' in dir(資料))
可迭代的一定可以被for迴圈
迭代器協議: 含有__iter__和__next__方法
迭代器一定可迭代,可迭代的通過呼叫iter()方法就能得到一個迭代器
迭代器的特點:
    很方便使用,且只能取所有的資料取一次
    節省記憶體空間

2,生成器

生成器:
生成器的本質就是迭代器
生成器的表現形式:
    生成器函式
    生成器表示式
生成器函式:
    含有yield關鍵字的函式就是生成器函式
    特點:
        呼叫函式的之後函式不執行,返回一個生成器
        每次呼叫next方法的時候會取到一個值
        直到取完最後一個,在執行next會報錯

3,從生成器中取值的幾個方法

# 從生成器中取值的幾個方法
    # next
    # for
    # 資料型別的強制轉換 : 佔用記憶體(這個缺點很厲害)



#method one
def generator():
    for i in range(10):
        yield '哇哈哈%s'%i

g = generator()  #呼叫生成器函式得到一個生成器
print(list(g))

輸出結果:
[‘哇哈哈0’, ‘哇哈哈1’, ‘哇哈哈2’, ‘哇哈哈3’, ‘哇哈哈4’, ‘哇哈哈5’, ‘哇哈哈6’, ‘哇哈哈7’, ‘哇哈哈8’, ‘哇哈哈9’]

#method two
def generator():
    for i in range(10):
        yield '哇哈哈%s'%i

g = generator()  #呼叫生成器函式得到一個生成器
ret = g.__next__()     #每一次執行g.__next__就是從生成器中取值,預示著生成器函式中的程式碼繼續執行
print(ret)


num = 0
for i in g:
    num += 1
    if num > 5:
        break
    print(i)

輸出結果:
哇哈哈0
哇哈哈1
哇哈哈2
哇哈哈3
哇哈哈4
哇哈哈5

二,生成器函式進階

1,send的使用

def generator():
    print(123)
    content = yield 1
    print('=======', content)
    print(456)
    yield 2
    ''''''
    yield

g = generator()
ret = g.__next__()
print('***', ret)
ret = g.send('Hello python')   #send的效果和next一樣
print('***', ret)


# send 獲取下一個值的效果和next基本一致
# 只是在獲取下一個值的時候,給上一yield的位置傳遞一個數據
# 使用send的注意事項
    # 第一次使用生成器的時候 是用next獲取下一個值
    # 最後一個yield不能接受外部的值

輸出結果:
123
*** 1
======= Hello python
456
*** 2

2,獲取移動平均值

def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum / count

avg_g = average()
avg_g.__next__()   #明確這行程式碼,會執行到什麼位置。
avg1 = avg_g.send(85)
avg1 = avg_g.send(56)
avg1 = avg_g.send(58)
avg1 = avg_g.send(56)
avg1 = avg_g.send(18)
avg1 = avg_g.send(56)
print(avg1)

輸出結果:
54.833333333333336

3,預激生成器的裝飾器

def init(func):   #裝飾器
    def inner(*args, **kwargs):
        g = func(*args, **kwargs)    #g = average()
        g.__next__()
        return g
    return inner

@init  #相當於執行: average = init(average)
def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum/count

avg_g = average()   #===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)
ret = avg_g.send(30)
print(ret)
ret = avg_g.send(40)
print(ret)

輸出結果:
10.0
15.0
20.0
25.0

4,補充一點python3的新語法

# 這是之前的方法實現
def generator1():
    a = 'abc'
    b = '123'
    for i in a:
        yield i
    for i in b:
        yield i

g1 = generator1()
for i in g1:
    print(i)

print('0000000000000000000000000000')

#python 3 新方法
def generator2():
    a = 'abc'
    b = '123'
    yield from a
    yield from b

g2 = generator2()
for i in g2:
    print(i)

輸出結果:
a
b
c
1
2
3
0000000000000000000000000000
a
b
c
1
2
3

總結:

send
    send的作用範圍和next一模一樣
    第一次不能用send
    函式中的最後一個yield不能接受新的值

計算移動平均值的例子
預激生成器的裝飾器的例子
yield from

三,生成器表示式

1,列表推導式

'''
列表推導式:
print([i*i for i in range(10)])
'''

#case1
egg_list = ['雞蛋%s' % i for i in range(10)]    #列表推導式
print(egg_list)

#case2
#for 迴圈
egg_list = []
for i in range(10):
    egg_list.append('雞蛋%s'%i)
print(egg_list)

輸出結果:
[‘雞蛋0’, ‘雞蛋1’, ‘雞蛋2’, ‘雞蛋3’, ‘雞蛋4’, ‘雞蛋5’, ‘雞蛋6’, ‘雞蛋7’, ‘雞蛋8’, ‘雞蛋9’]
[‘雞蛋0’, ‘雞蛋1’, ‘雞蛋2’, ‘雞蛋3’, ‘雞蛋4’, ‘雞蛋5’, ‘雞蛋6’, ‘雞蛋7’, ‘雞蛋8’, ‘雞蛋9’]

2,生成器表示式

g = (i for i in range(10))
print(g)
for i in g:
    print(i)

輸出結果:
<generator object at 0x0000017D4F7DED58>
0
1
2
3
4
5
6
7
8
9

列表推導式 和 生成器表示式 區別:
括號不一樣
返回的值不一樣 === 幾乎不佔用記憶體,但是列表表示式 是直接把全部的值全部給出,非常佔用記憶體

四,各種推導式

1,基本概念

#[每一個元素或者是和元素相關的操作 for 元素 in 可迭代資料型別]    #遍歷之後挨個處理
#[滿足條件的元素相關的操作 for 元素 in 可迭代資料型別 if 元素相關的條件]   #篩選功能

case1:

#找到30以內所有能被3整除的數
ret = [i for i in range(30) if i% 3 == 0]  #完整的列表推導式
g = (i for i in range(30) if i% 3 == 0)  #完整的生成器表示式
print(ret)
print(g)
for i in g:
    print(i)

輸出結果:
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
<generator object at 0x0000020E3BF0ED58>
0
3
6
9
12
15
18
21
24
27

case2:

# 找到巢狀列表中名字含有兩個‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]


ret1 = [name for lst in names for name in lst if name.count('e') == 2]
ret2 = (name for lst in names for name in lst if name.count('e') == 2)
print(ret1)
print(ret2)

輸出結果:
[‘Jefferson’, ‘Wesley’, ‘Steven’, ‘Jennifer’]
<generator object at 0x0000019DA7FAED58>

2,字典推導式

# 例一:將一個字典的key和value對調
mcase = {'a': 10, 'b': 34}
# 結果:{10:'a' , 34:'b'}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)

輸出結果:
{10: ‘a’, 34: ‘b’}

#例二:合併大小寫對應的value值,將k統一成小寫
#mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
#{'a':10+7,'b':34,'z':3}

# note;像這種很長的推導式一定要從後邊的for迴圈開始看

mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
print(mcase_frequency)

輸出結果:
{‘a’: 17, ‘b’: 34, ‘z’: 3}

3,集合推導式

#集合推導式,自帶結果去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)


#各種推導式 : 生成器 列表 字典 集合
    #遍歷操作
    #篩選操作

輸出結果:
{1, 4}