可迭代物件
【1】什麼叫迭代?
迭代其實就是更新換代,每一次迭代的過程都需要依賴上一次的結果
例如
# 屬於迭代,每次結果都依據上一次結果
# 例一
n = 1
while True:
print(n)
n +=1
# 例二
l1 = [1,2,3,4,5,6,7,8,9]
n = 0
while n < len(l1):
print(l1[n])
n += 1
【2】什麼是可迭代物件
1.內建有__iter__方法的都可以稱為可迭代物件
2.__iter__該型別程式碼的讀法>>>:雙下iter方法
【3】哪些資料是可迭代物件
依次列舉並嘗試呼叫雙下iter方法即可
可迭代(支援for迴圈):字串(str),字典(dict),元組(tuple),列表(list),集合(set)
不可迭代:整型(int), 浮點型(float),布林型(bool)
迭代器物件
【1】什麼是迭代器物件
可迭代物件呼叫雙下iter方法之後生成的結果就是迭代器物件
【2】迭代器物件的特徵
含有雙下iter方法又含有雙下next方法
含有__iter__又含有__next__
s=[1,2,3,4,5,6,7,8,9,10]
res = s.__iter__()
print(res) # <list_iterator object at 0x000001BAE2829780>
'''
迭代器物件 iterator object
'''
pice = res.__next__()
print(pice)
# 1 輸出一次 依次彈出列表中的一個元素
【3】如何理解迭代器物件
迭代器物件能夠極大的節省儲存空間
- eq:類似於哆啦A夢的口袋,不用就是一個口袋面積,用的時候可以從中取出很多資料
【4】迭代器物件如何取值
呼叫雙下next方法即可,如果取完了就會報錯
【5】擴充瞭解
1.有很多雙下方法其實都有簡便寫法,但不是全部
'''
__方法名__ 等價 方法名()
最常見的兩個是
__iter__ iter()
__next__ next()
'''
2.有一些可迭代物件本身也是迭代器物件:>>> 檔案物件
3.可迭代物件呼叫一次雙下iter方法程式設計迭代器物件,如果繼續呼叫,結果還是迭代器物件本身
for迴圈內部原理
'''
for迴圈底層原理
for 變數名 in 可迭代物件:
迴圈體程式碼
1.會將in後面的資料呼叫__iter__()變成迭代器物件
所以就解釋了為什麼檔案物件也可以for迴圈,因為本身就是迭代器物件,再次呼叫不變
2.針對產生的迭代器物件依次呼叫__next__()方法迭代取值
3.當取值完之後,會自動處理報錯並退出迴圈
'''
user_dict = {'name':'silence','age':18,'password':123}
# 1.先轉換成迭代器物件
# res= user_dict.__iter__()
res = iter(user_dict)
# 2. 迭代取值
while True:
# print(res.__next__())
try:
print(next(res))
except Exception as e:
# 結束while迴圈
break
# name
# age
# password
迭代取值與索引取值的對比
1.索引取值
1.優勢:
- 可以反覆獲取相同元素,並沒有固定的方向
2.劣勢:
- 只能支援有序的容器型別,無序的無法取值相容性沒有迭代取值高
2.迭代取值
1.優勢:
- 相容所有的容器型別
- 不使用索引進行取值
- 字典是不支援索引取值的
- 取到這個值的時候就會儲存到當前的狀態,下一次從這個位置開始向下取值
2.劣勢:
- 取值的順序永遠都是從左往右,並且無法重複獲取,取完就完了
- 除非取值取到盡頭,否則永遠不知道終止索引在哪裡
- 迭代同一個物件只能重新建立
- 呼叫 next 取值的前提是 已經生成並且得到了一個迭代器物件
生成器物件(自定義迭代器)
def index():
print('你還記得我嘛')
# yield 123
yield 123,111
# 沒有呼叫之前就是一個普通的函式
'''
當函式體程式碼中含有yield關鍵字
第一次呼叫函式並不會執行函式體程式碼
而是將函式變成了生成器
'''
# print(index) # <function index at 0x000001FF8B493E20>
# 加括號呼叫並接收結果:不執行程式碼,而是變成生成器物件(迭代器)
res = index()
# print(res) #<generator object index at 0x00000204F3AE6960> 變成生成器物件
# 變成生成器之後呼叫__next__就會開始執行函式體程式碼
# print(next(res)) #123 yield有點像return功能
print(next(res)) #(123, 111)
'''
生成器物件也是節省儲存空間的 特性與迭代器物件一致
'''
def index():
print('你還記得我嘛')
yield 123
print('是不是忘記我了')
yield 123,111
'''
如果函式體程式碼中含有多個yield關鍵字,每執行一次__next__可以返回後面的值,並且讓程式碼停留在yield位置
再次執行__next__基於上次的位置往後執行到下一個yield關鍵字處
如果沒有了,再執行就會報錯 StopIteration
'''
res = index()
print(next(res)) # 123
print(next(res)) # (123,111)
print(next(res)) # 報錯
# 用for迴圈也可以 直接for自帶報錯處理
def index():
yield 123
yield 123,111
res = index()
for i in res:
print(i)
#123
#(123, 111)
自定義range方法
range方法其實是一個可迭代物件
'''
需求:透過生成器模擬range方法
for i in range(1,10):
print(i)
'''
# 先以兩個引數的range引數為例
def my_range(start, end):
while start < end:
yield start
start += 1
for i in my_range(1,10):
print(i)
# 初步實現之後 在考慮不同引數情況 一個引數 三個引數
# 先針對一個
'''
end可以不傳值 應該設定成預設引數 end=None
程式碼層面做判斷 將形引數據做替換處理
end=start
start=0
'''
def my_range(start, end=None):
if not end:
end = start
start = 0
while start < end:
yield start
start += 1
for i in my_range(10):
print(i)
# 針對三個引數情況
'''
給函式新增第三個形參 並且設定成預設引數 預設值是1 step=1
每次遞增只需要遞增step的數值即可
'''
def my_range(start, end=None, step=1):
if not end:
end = start
start = 0
while start < end:
yield start
start += step
for i in my_range(1, 10, 2):
print(i)# 1,3,5,7,9
for i in my_range(10):
print(i)# 0,1,2,3,4,5,6,7,8,9
for i in my_range(1,10):
print(i) # 1,2,3,4,5,6,7,8,9
yield關鍵字作用
1.在函式體程式碼中出現 可以將函式變成生成器
2.在執行過程中,可以將後面的值返回出去,類似於return
3.還可以暫停住程式碼的執行
4.還可以接收外界的傳值
yield接收外界傳值 用語法.send()
def eat(name):
print(f'{name} 準備乾飯')
while True:
food = yield
print(f'{name} 正在吃{food}')
res = eat('大胃王')
# 想執行一次,如果想執行多次直至結束 可以直接用for迴圈
res.__next__()
# yield 可以接收外部傳值
res.send('魚香肉絲') # 可以給yield傳值,並且自動呼叫一次__next__方法
res.send('宮保雞丁')
# 大胃王 準備乾飯
# 大胃王 正在吃魚香肉絲
# 大胃王 正在吃宮保雞丁
生成器表示式
也是為了節省儲存空間
重點:
生成器內部的程式碼只有在呼叫雙下next迭代取值的時候才會執行
面試題示例
# 普通求和函式
def add(n,i):
return n+i
# 生成器物件 返回 1,2,3
def test():
for i in range(4):
yield i
# 將test函式變成生成器物件
g=test()
# 簡單for迴圈
for n in [1,10]:
g = (add(n,i) for i in g)
'''
從上到下還沒有呼叫函式 只有執行兩次for迴圈,只有對g進行迭代取值是才進行程式碼操作
第一次for迴圈
g = (add(n,i) for i in g)
第二次for迴圈
g = (add(n,i) for i in (add(n,i) for i in g))
再list(g)呼叫函式時 第二次for迴圈裡的n都為10,而i是0
所以第一次呼叫的時候就是10+10 20是起始數
'''
print(n)
res = list(g)# list底層就是for迴圈 相當於對g做了迭代取值操作
print(res)
# A .res=[10,11,12,13]
# B .res=[11,12,13,14]
# C .res=[20,21,22,23] # 正確答案
# D .res=[21,22,23,24]
# 正確答案是c 訣竅就是抓n是多少即可