[007]Python的函數_迭代器和生成器_全棧基礎

您好!此筆記的文本和代碼以網盤形式分享於文末!

因個人能力有限,錯誤處歡迎大家交流和指正!基礎部分內容簡單,但多且零散!

Python迭代器和生成器
迭代:可以將某個數據集內的數據“一個挨着一個的取出來”,就叫做迭代。
可迭代數據類型:字符串、列表、元組、字典、集合
可迭代協議:可迭代協議的定義非常簡單,就是內部實現了__iter__方法
迭代器:迭代器是一個可以記住遍歷的位置的對象,迭代器遵循迭代器協議:必須擁有__iter__方法和__next__方法。節省內存
生成器:自己實現迭代器的功能代碼叫生成器,在調用生成器運行的過程中,每次遇到 yield 時函數會暫停並保存當前所有的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。
生成器的本質:就是迭代器,特點是惰性運算,開發者自定義;
生成器函數:一個包含yield關鍵字的函數就是一個生成器函數;
生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表
生成器優點:延遲計算,一個返回一個結果,不會一次性生成所有結果,對於大數據處理很有意義。並且提高代碼的可讀性
用法 栗子 結果
迭代 # 將數據集內的元素一個接一個取出來的過程叫做迭代
for i in [1, 2, 3, 'a']:
    print(i)
1
2
3
a
可迭代的數據類型 # 字符串、列表、元組、字典、集合都是可迭代的
from collections import Iterable

s1 = '12ab'
li1 = [1, 2, 'a', 'b']
tu1 = (1, 2, 'a', 'c', )
di1 = {'a': 1, 'b': 2, }
se1 = {1, 2, 3, 4}
a = 123456789

print(isinstance(s1, Iterable))
print(isinstance(li1, Iterable))
print(isinstance(tu1, Iterable))
print(isinstance(di1, Iterable))
print(isinstance(se1, Iterable))
print(isinstance(a, Iterable))
True
True
True
True
True
False
可迭代協議:
內部實現了__iter__方法
# 對比可迭代數據類型中都有實現__iter__方法
print(dir(s1))
print(dir(tu1))
print(dir(a))
 
不同數據類型
中__iter__方法的包含
字典和集合的無序特性
其無__setstate__方法
print(set(dir(s1.__iter__())) - set(dir(s1)))
print(set(dir(li1.__iter__())) - set(dir(li1)))
print(set(dir(tu1.__iter__())) - set(dir(tu1)))
print(set(dir(di1.__iter__())) - set(dir(di1)))
print(set(dir(se1.__iter__())) - set(dir(se1)))
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__'}
{'__next__', '__length_hint__'}
三個方法的使用和介紹 iter_1 = li1.__iter__()

# 獲取迭代器中元素的長度
print(iter_1.__length_hint__())
# 根據索引值指定位置開始迭代
print(iter_1.__setstate__(2))

# 一個接一個的取值
print(iter_1.__next__())
print(iter_1.__next__())
4
None
a
b
__next__方法
及其異常處理
# __next__() 方法會由於無元素可取報異常
# 使用異常處理機制來處理掉異常
iter_1 = li1.__iter__()
while True:
    try:
        item = iter_1.__next__()
        print(item)
    except StopIteration:
        break
1
2
a
b
range()
是可迭代對象
但不是迭代器
from collections import Iterator
# range()關於iter和next方法測試
# 在range()執行後的內部是否有next和iter方法
print('__next__' in dir(range(12)))
print('__iter__' in dir(range(12)))

# 是否可迭代
print(isinstance(range(12), Iterable))
# 是否是迭代器
print(isinstance(range(12), Iterator))
False
True
True
False
生成器函數 # 生成器函數
import time

def genrator_func():
    a = 1
    print('定義a 變量')
    yield a  # 暫停,等待下次next()方法的執行
    b = 2
    print('定義b變量')
    yield b
    c = 3
    print('定義c變量')
    yield c

gen1 = genrator_func()
print('g1: ', gen1)
print('-'*17)
print(next(gen1))
time.sleep(1)
print(next(gen1))
g1:  <generator object genrator_func at 0x000001BB7B30F990>
-----------------
定義a 變量
1
定義b變量
2
生成器函數二 def produce():
    """
    生產定製手模
    月生產力最多13個
    """
    for i in range(13):
        yield '生產了第%d個手模' % i

produce_g = produce()

# 接受客戶定製訂單
print('請輸入訂單數量:')
num = int(input())

if num > 10:
    print('抱歉超過本月生產力,請返回重新輸入!')

j = 0
for i in produce_g:
    if j < num <= 10:
        print(i)
        j += 1
    else:
        break

# 樣品生產
print('樣品展示:', '\n', produce_g.__next__())
print(next(produce_g))
請輸入訂單數量:
11
抱歉超過本月生產力,請返回重新輸入!
樣品展示:
 生產了第1個手模
生產了第2個手模
生成器監聽文件輸入列子    
.send應用
時間間隔可更清晰的
看到運行順序
import time

def generator():
    print('開始')
    content = yield '返回1'
    print('第一個yield的值:', content)
    print('Two')
    content2 = yield '返回2'
    print('第二個yield的值:', content2)
    print('Three')
    content3 = yield "返回3"
    print('第三個yield的值:', content3)
    print('four')
    yield '第4次返回'

g = generator()
# 第一次運行只能使用next或send(None)
print(g.send(None))
print('\n')
time.sleep(6)
# send 作用相當於next方法並將傳遞參數爲 yield的返回值
print(g.send('第2次傳入參數'))
print('\n')
time.sleep(6)
# next方法 相當於 send(None) 即 temp = None
print(g.__next__())
print('\n')
time.sleep(6)
# 最後一個yield不能接受外部的值
print(g.send(None))
開始
返回1


第一個yield的值: 第2次傳入參數
Two
返回2


第二個yield的值: None
Three
返回3


第三個yield的值: None
four
第4次返回
計算移動平均值 import time

def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        print("第%d次執行" % count)
        term = yield average
        total += term
        count += 1
        average = total / count
        print('第%d次接收的term值爲:' % count)
        print(term)

g_avg = averager()
print('第一次調用send')
print('第一次生成器yield返回值爲', next(g_avg))
print('\n')
time.sleep(6)
print('第二次調用send')
print('第二次生成器yield返回值爲', g_avg.send(15))
print('\n')
time.sleep(6)
print('第三次調用send')
print('第三次生成器yield返回值爲', g_avg.send(30))
print('\n')
time.sleep(6)
print('第四次調用send')
print('第四次生成器yield返回值爲', g_avg.send(10))
第一次調用send
第0次執行
第一次生成器yield返回值爲 None


第二次調用send
第1次接收的term值爲:
15
第1次執行
第二次生成器yield返回值爲 15.0


第三次調用send
第2次接收的term值爲:
30
第2次執行
第三次生成器yield返回值爲 22.5


第四次調用send
第3次接收的term值爲:
10
第3次執行
第四次生成器yield返回值爲 18.333333333333332
計算移動平均值
預激協程
def init(func):
    def inner(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        print("第%d次執行" % count)
        term = yield average
        total += term
        count += 1
        average = total / count
        print('第%d次接收的term值爲:' % count)
        print(term)

g_avg = averager()
print('\n', '開始')
print('第一次調用send')
print('第一次生成器yield返回值爲', g_avg.send(15))
print('\n')
print('第二次調用send')
print('第二次生成器yield返回值爲', g_avg.send(30))
print('\n')
print('第三次調用send')
print('第三次生成器yield返回值爲', g_avg.send(10))
第0次執行

 開始
第一次調用send
第1次接收的term值爲:
15
第1次執行
第一次生成器yield返回值爲 15.0


第二次調用send
第2次接收的term值爲:
30
第2次執行
第二次生成器yield返回值爲 22.5


第三次調用send
第3次接收的term值爲:
10
第3次執行
第三次生成器yield返回值爲 18.333333333333332
yield from def gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i

print(list(gen1()))

def gen2():
    yield from 'AB'
    yield from range(3)

print(list(gen2()))
['A', 'B', 0, 1, 2]
['A', 'B', 0, 1, 2]
列表推導式1 # 30以內所有能被3整除的數
multiples = [i for i in range(30) if i % 3 is 0]
print(multiples)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
生成器表達式1 # 生成器表達式
multiples1 = (i for i in range(30) if i % 3 is 0)
print(multiples1)
print(next(multiples1))
print(multiples1.__next__())
print(next(multiples1))
<generator object <genexpr> at 0x0000011DA10FF8E0>
0
3
6
列表推導式2
又稱列表解析
缺點:內存佔用大
機器容易卡死
multiples = [i for i in range(30) if i % 3 is 0]

def squared(x):
    return x ** 2

# 30以內所有能被3整除的數的平方
multiples2 = [squared(i) for i in range(30) if i % 3 is 0]
print(multiples2)
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
生成器表達式2
優點:幾乎不佔內存
multiples3 = (squared(i) for i in range(30) if i % 3 is 0)
print(multiples3)
print(next(multiples3))
print(multiples3.__next__())
print(next(multiples3))
<generator object <genexpr> at 0x000002388D6BF990>
0
9
36
列表推導式3 # 嵌套列表中查詢 兩個‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

eenames = [name for lst in names for name in lst if name.count('e') >= 2]
print(eenames)
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
生成器表達式3 eenames1 = (name for lst in names for name in lst if name.count('e') >= 2)
print(eenames1)
print(next(eenames1))
print(eenames1.__next__())
print(next(eenames1))
<generator object <genexpr> at 0x0000024A95F9F9E8>
Jefferson
Wesley
Steven
python內置函數sum # 使用迭代器協議訪問對象的函數sum
ret1 = sum(x ** 2 for x in range(4))
print(ret1)
14
字典推導式1 # 將字典的Key和Value對調
dic1 = {'a': 1, 'b': 2, }
dic1_frequency = {dic1[k]: k for k in dic1}
print(dic1_frequency)
{1: 'a', 2: 'b'}
字典推導式2 # 合併大小寫對應的 value值,將K統一成小寫
dic2 = {'a': 1, 'b': 2, 'A': 7, 'D': 6, }
print(list(k for k in dic2.keys()))
print(list(l1.lower() for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.lower()) for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.lower(), 0) for k in dic2.keys() for l1 in k))

print(list(l1.upper() for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.upper()) for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.upper(), 0) for k in dic2.keys() for l1 in k))


dic2_sortout = {k.lower(): dic2.get(k.lower(), 0) + dic2.get(k.upper(), 0) for k in dic2.keys()}
print(dic2_sortout)
['a', 'b', 'A', 'D']
['a', 'b', 'a', 'd']
[1, 2, 1, None]
[1, 2, 1, 0]
['A', 'B', 'A', 'D']
[7, None, 7, 6]
[7, 0, 7, 6]
{'a': 8, 'b': 2, 'd': 6}
集合推導式 # 計算列表中每個值的平方且自帶去重
squared = {x ** 2 for x in [1, -2, -1, 3]}
print(squared)
{1, 4, 9}
拓展1 def demo():
    for i in range(4):
        yield i


g = demo()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1))
print(list(g2))
print('\n')

g3 = demo()
g4 = (i for i in g3)
g5 = (i for i in g4)
print(list(g5))
print(list(g4))
print('\n')

g6 = demo()
g7 = (i for i in g6)
g8 = (i for i in list(g7))
print(list(g8))
print('\n')

g9 = demo()
g10 = (i for i in g9)
g11 = (i for i in list(g10))
print(list(g11))
print(list(g10))
print('\n')

g12 = demo()
g13 = (i for i in g12)
print(list(g13))
g14 = (i for i in list(g13))
print(list(g11))
print('\n')
[0, 1, 2, 3]
[]


[0, 1, 2, 3]
[]


[0, 1, 2, 3]


[0, 1, 2, 3]
[]


[0, 1, 2, 3]
[]
拓展2 def add(n, i):
    return n+i


def test():
    for i in range(4):
        yield i


g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)

print(list(g))
[20, 21, 22, 23]
拓展2 def add(n, i):
    return n+i

def test():
    for i in range(4):
        yield i

print('g:')
g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)
print(list(g))

print('g1:')
g1 = test()
for n in [10, 1]:
    g1 = (add(n, i) for i in g1)
print(list(g1))

print('g12:')
g10 = test()
for n in [1, ]:
    g11 = (add(n, i) for i in g10)
for n in [10, ]:
    g12 = (add(n, i) for i in g11)
print(list(g12))
g:
[20, 21, 22, 23]
g1:
[2, 3, 4, 5]
g12:
[20, 21, 22, 23]

願有更多的朋友,在網頁筆記結構上分享更邏輯和易讀的形式:

鏈接:暫無
提取碼:暫無

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章