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}