2022.3.23學習筆記
2022.3.23學習筆記
- 可迭代物件
- 迭代器物件
- for迴圈的內部原理
- 異常處理
- for迴圈的本質(程式碼模擬)
- 迭代取值與索引取值的對比
一、可迭代物件
1、迭代的概念
迭代就是更新換代,每一次迭代都是基於上一次的結果,類似遊戲版本的更新
特徵:每一次的結果都不一樣或者都有更新才叫做迭代
while True: print(123) # 單純的迴圈不叫迭代 n = 1 while True: print(n) n +=1 # 每次都不一樣的,這樣的迴圈才屬於迭代 # 迭代取值 l1 = [11, 22, 33, 44, 55] n = 0 while n < len(l1): print(len(n)) n += 1
2、可迭代物件
內建有__iter__方法的都可成為可迭代物件,一般支援for迴圈的都是可迭代物件,如字串、列表、字典、元組、集合、檔案物件等
# 可迭代物件可以用.__iter__的方式進行呼叫
# __iter__讀法:雙下iter方法,不要讀槓槓
s = 'jsdon'
s.__iter__
二、迭代器物件
1、概念
可迭代物件呼叫__iter__方法後生成的結果就是迭代器物件
2、特徵
含有__iter__()方法和__next__()方法 s = 'jsdon' res = s.__iter__() # 將s轉為迭代器物件 res.__next__() # 使用next呼叫res這個迭代器物件,表示取第一個元素
3、迭代器物件的理解
作用:極大節省儲存空間
類似哆啦a夢的口袋,不用的時候就是一個口袋,用的時候可以拿出很多東西
4、迭代器物件如何取值
呼叫__next__()方法即可
注意:如果資料取完了則會直接報錯!!!
# for迴圈的底層依據就是迭代器物件
5、迭代器物件補充說明
(1)轉化及呼叫的簡易寫法
__iter__() == iter()
__next__() == next()
(2)檔案物件
檔案物件本身就是迭代器物件,無須使用iter()呼叫
(3)多次呼叫iter()的結果
可迭代物件呼叫1次iter()會轉化成迭代器物件,如果繼續呼叫結果還是迭代器物件本身
res = s.__iter__() res1 = s.__iter__().__iter__().__iter__() res == res1 # 兩個迭代器物件是一樣的
(4)迭代取值的要求
s = 'jason'
print(s.__iter__().__next__()) # j
print(s.__iter__().__next__()) # j
print(s.__iter__().__next__()) # j
print(s.__iter__().__next__()) # j
print(s.__iter__().__next__()) # j
思考?為什麼以上呼叫了5次結果一樣呢?
這是因為s轉化成迭代器物件之後需要一個變數名接收,不然再次呼叫還是從頭開始的,因此要這樣使用
s = 'jason'
res = s.__iter__()
print(res.__next__()) # j
print(res.__next__()) # a
print(res.__next__()) # s
print(res.__next__()) # o
print(res.__next__()) # n
三、for迴圈內部原理
先看for迴圈的結構:
for 變數名 in 可迭代物件:
迴圈體程式碼
經過之前的學習,in後面相當於是將可迭代物件iter()一下變成迭代器物件,然後迴圈取裡面的值,直到取完
l1 = [1, 2, 3, 4, 5, 6, 7]
res = l1.__iter__()
n = 0
while n < len(l1):
print(res.__next__())
n +=1 # 這裡如果不進行人為計數,就會出現異常,也就是報錯
所以什麼是異常處理呢?
四、異常處理
1、什麼是異常
程式碼執行出錯之後就是異常,異常會導致程式立刻停止,因此我們再編寫程式碼的時候需要極力避免(異常的外號叫:bug)
2、異常資訊的組成部分(報錯)
先看下面這個報錯資訊
1.Traceback (most recent call last):
2. File "/Users/jiboyuan/PycharmProjects/day16/05 異常處理.py", line 3, in <module>
name
3.NameError: name 'name' is not defined
序號1:line關鍵字所在的一行,用於提示哪一行報錯,點選藍色字型即可定位,如果報錯資訊很長,那麼一般最後一個才是
序號2:NameError是錯誤的型別中的一種,還有很多其他型別
序號3:name 'name' is not defined是具體的報錯原因,一般也是解決報錯的方法
3、異常的分類
1.語法異常
最基礎的語法結構,出現了會立即報錯,pycharm中會出現紅色波浪線
2.邏輯異常
不會直接報錯,語法裡有這個操作,但是亂用,比如:
name = 'jason'
name.append() # 不會立馬報錯,但是字串不可以使用列表內建方法,執行程式便會報錯
如果邏輯異常,儘快修改即可
4、異常型別
舉幾個例子,如下
1.print(name) # NameError 名字錯誤
2.l1 = [1, 2, 3]
print(l1[100]) # IndexError 索引錯誤
3.dict = {'name':'jason'}
print(dict['age']) # KeyError 鍵錯誤
4.int('jason') # ValueError 值錯誤
......
還有很多異常的型別,需要再改bug的時候多熟悉
五、異常處理實操
1、基本語法結構
try:
可能會出錯的程式碼
except 錯誤型別1 as e: # e指代錯誤提示資訊
針對1的處理措施
except 錯誤型別2 as e:
針對2的處理措施
except 錯誤型別3 as e:
針對3的處理措施
...
2、統一錯誤型別處理
由於有時候自己也不清楚是什麼bug,使用下面的語法結構,可以對任意錯誤型別進行操作,也叫“萬能異常”
try:
可能會出錯的程式碼
except Exception as e:
統一的額處理措施
但是並不是以後都可以用這種方式,因為異常處理的準則就是被檢測的程式碼越少越好,儘量少用
3、異常處理了解篇
(1)結合else使用
try檢測的程式碼沒有發生異常,正常執行完畢後會執行else的子程式碼
try: # 檢測程式碼有無異常
可能會出錯的程式碼
except Exception as e: # 檢測異常走except子程式碼
統一的處理措施
else: # 檢測無異常走else子程式碼
可能會出錯的程式碼沒有出錯 最後走else子程式碼
(2)結合finally使用
無論try檢測的程式碼有無異常最後都會執行finally子程式碼
try: # 檢測程式碼有無異常
可能會出錯的程式碼
except Exception as e: # 檢測異常走except子程式碼
統一的處理措施
else: # 檢測無異常走else子程式碼
可能會出錯的程式碼沒有出錯 最後走else子程式碼
finally: ####### 最後一步都會走finally
無論上面有沒有異常,最後都會走這一步
(3)assert斷言
name = 'jaosn'
assert isinstance(name,str)
(4)raise主動報錯(需要掌握)
raise NameError('就是要報錯,怎麼了')
因為是主動報錯,所以明確知道是什麼錯誤
六、for迴圈的本質
瞭解了異常處理的一些知識,我們再回到for迴圈的原理上
l1 = [1, 2, 3, 4, 5, 6, 7]
res = l1.__iter__()
n = 0
while n < len(l1):
print(res.__next__())
n +=1 # 這裡如果不進行人為計數,就會出現異常,也就是報錯
剛才說了,這裡如果不寫n += 1,資料取完後就會報錯,結合異常處理的知識我們可以這樣做:
l1 = [1, 2, 3, 4, 5, 6, 7]
res = l1.__iter__()
while True:
try:
print(res.__next__()) # 檢測這一行程式碼
except StopIteration as e: # 執行時瞭解到報錯StopIteration
break # 報錯直接退出迴圈
這樣在我們知道報錯的型別就可以加以相應的處理措施啦,是不是很神奇
七、迭代取值與索引取值的對比
1、索引取值
優勢:可以反覆取相同元素,沒有固定方向
劣勢:只能支援有序的容器型別,且相容性沒有迭代取值高
2、迭代取值
優勢:相容所有容器型別
劣勢:永遠是順序取值,且無法重複獲取,取完就結束
注意:迭代器裡面的東西,取一個少一個,取完就沒了