學習python課程第二十五天
一. 三層結構:
1. 使用者檢視層 : 負責與使用者互動 (展示資料,收集資料)
2. 業務邏輯層 : 負責對使用者傳入的資料, 進行 驗證, 判斷, 組裝
3. 資料訪問層 : 負責將業務邏輯層輸出後的資料進行持久化儲存
二 . 異常處理:
1. 什麼是異常:
異常,字面意思就是非常規情況,平時我們看到的異常其實是異常的結果.
異常是錯誤發生前的一種訊號.
如果沒有人來處理這個訊號, 程式就會中斷執行並丟擲錯誤資訊.
我們之所以學異常處理, 為的是讓我們的程式更加穩定.增加健壯性. 不容易崩潰
2. 異常的分類:
1. 語法檢測異常 :
這種異常是最低階的異常, 絕對不應給犯,
當然, 這種也很好避免. 如果在編譯器上寫, 會自動提示.
如果是文字編輯器, 在執行程式碼前, 直譯器會檢查語法.
2. 執行時異常 (邏輯異常) :
這種異常,只有在程式碼被執行時才能發現
我們要處理的重點就是執行時異常
特點 : 在沒有執行程式碼前,是無法發現的,
如果執行時異常已經發生並且沒有正確處理它,
就會丟擲錯誤資訊, 並且中斷程式的執行.
這是我們學習異常要解決的問題.
3. 異常的組成 :
異常的組成分為三個部分 :
1. 追蹤資訊. (具體發生的位置. 以及函式的呼叫順序)
2. 異常的型別. (描述了為什麼發生錯誤的型別)
3. 異常的訊息. (詳細的錯誤資訊)
4. 常見的異常:
AttributeError 試圖訪問一個物件沒有的樹形,比如foo.x,但是foo沒有屬性x
IOError 輸入/輸出異常;基本上是無法開啟檔案
ImportError 無法引入模組或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;程式碼沒有正確對齊
IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典裡不存在的鍵
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予物件的變數
SyntaxError Python程式碼非法,程式碼不能編譯(個人認為這是語法錯誤,寫錯了)
TypeError 傳入物件型別與要求的不符合
UnboundLocalError 試圖訪問一個還未被設定的區域性變數,基本上是由於另有一個同名的全域性變數.
導致你以為正在訪問它
ValueError 傳入一個呼叫者不期望的值,即使值的型別是正確的
5. 異常的處理 :
為了保證程式的健壯性與容錯性, 即在遇到錯誤時程式不會崩潰 我們需要對異常進行處理.
1. 常用的異常處理 :
如果錯誤發生的條件是可預知的, 我們需要用 if 進行處理, 在錯誤發生之前進行預防.
示例 :
AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age為字串形式的整數時,下列程式碼才不會出錯,該條件是可預知的 age=int(age) if age == AGE: print('you got it') break
如果錯誤發生的條件是不可預知的, 則需要用到 try ... except ... :在錯誤發生之後進行處理
基本語法為 :
try :
# 被檢測的程式碼塊
except # 異常的型別 :
# try 中一旦檢測到異常, 就執行這個位置的邏輯
示例:
try:
f = open('a.txt')
g = (line.strip() for line in f)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
except StopIteration:
f . close()
2 多分支
s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) 3 萬能異常Exception
s1 = 'hello' try: int(s1) except Exception as e: print(e)
4 多分支異常與萬能異常 4.1 如果你想要的效果是,無論出現什麼異常,我們統一丟棄,或者使用同一段程式碼邏輯去處理他們,那麼騷年,大膽的去做吧.
只有一個Exception就足夠了。 4.2 如果你想要的效果是,對於不同的異常我們需要定製不同的處理邏輯,那就需要用到多分支了。
5 也可以在多分支後來一個Exception s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) except Exception as e: print(e)
2. 不常用的異常處理 :
try :
except :
else : (會在try 中沒有異常時執行)
示例 :
print('start')
try:
1/0
except Exception:
print ('炸了'!)
else:
print('else 執行了')
print('end...')
try:
except:
finally: (無論異常是否發生,最終都會執行 (要放到最後一個) )
示例 :
print('start')
try:
1/0
except Exception:
print ('炸了'!)
else:
print('else 執行了')
finally:
print('finally 執行了')
print('end...')
使用 finally 來回收資源
try:
f = open('a.txt','rt',encoding='utf-8')
f.read()
f.write('123')
except Exception:
print ('發生異常了')
finally:
print('關閉檔案')
f.close()
6. 主動丟擲異常 :
當程式中有一些限制,然而使用者沒有遵守,那我們可以主動丟擲異常.
語法. : raise 異常物件(異常的詳細資訊)
型別必須是BaseException的子類
示例:
age = input('請輸入整型的年齡')
if not age。isdigit():
raise TypeError ('你輸入的不是整型')
age = int(age)
print ('十年後你%s歲'%(age+10))
(有些使用者就不輸入整型,所以會導致程式爆炸.這就要用到raise了)
7. 斷言 :
斷言可以理解為, 斷定, 就是很清楚,很明確
什麼時候需要斷言 ?
下面的程式碼必須依賴上面程式碼的正確資料
語法 : assert 結果為bool的表示式
如果值為True 則繼續往下執行
如果值為False 丟擲異常 AssertionError 表示斷言失敗
沒有assert 也可以使用if 來用. assert僅僅是省略了程式碼
示例:
#第一部分程式碼. 負責產生一個列表
li = []
li.append(1)
li.append(2)
# 這裡一定要確保資料是有效的
# 第一種解決方式, 用丟擲異常 raise
if len(li) < 1:
raise ValueError('列表中沒有資料')
# 第二種解決方式, 斷言 assert
assert len(li) > 0
# 需要使用列表中的資料來完成任務. 如果沒有資料就無法完成
print(li[0])
print(li[0])
print(li[0])
8. 自定義異常 :
當系統提供的這些異常型別, 和你要描述的錯誤不匹配時,我們就需要自定義異常型別
寫法 :
class : 自定義異常型別名稱(BaseException):
總結:
之所以自定義異常型別,是為了更具體的描述你的錯誤,讓使用者一眼就可以看出來
關鍵點:
1. 如何自定義異常型別
2. 在except中, 使用as 來獲取異常物件, as可以給異常型別起別名,而且把異常型別的值賦給後面
的別名.
示例:
# 你隨便輸入一句話, 看我喜不喜歡, 不喜歡我就丟擲異常
class unlikeError (BaseException):
def __init__(self,msg):
self.msg = msg
text = input('輸入一段話')
if text == '你真帥'
print('你說的對')
else:
raise UnlikeError('你再看看 ?')
9 .異常處理的使用場景:
有的同學會這麼想, 學完了異常處理後,好強大, 我要為我的每一段程式都加上try...except. 幹毛線去
思考它會不會有邏輯錯誤啊, 這樣就很好啊, 多省腦細胞啊.
其實: 首先, try...except是你附加給你的程式的一種異常處理的邏輯. 與你的主要的工作是沒有關係的
這種東西加多了.會導致你的程式碼可讀性變差,
然後異常處理根本就不是你2b邏輯的擦屁股紙, 只有在錯誤發生的條件無法預知的情況下,才應該加上
try...except..
三. 網路程式設計 初識
.1. 為什麼要學習網路程式設計 ?
前兩次的專案: ATM購物車,和選課系統都是單機程式 , 寫出來只能自己玩.
但是我們以後進公司寫的程式百分之99都是網路程式, 所以現在要學習網路程式設計.
2. 應用軟體的構架 :
1. C / S
client(客戶端) ==== server(伺服器)
2. B / S
browser(瀏覽器) ==== server
網際網路中處處是C/S架構
如黃色網站是服務端,你的瀏覽器是客戶端(B/S架構也是C/S架構的一種)
騰訊作為服務端為你提供視訊,你得下個騰訊視訊客戶端才能看它的視訊)
C/S架構與socket的關係:
我們學習socket就是為了完成C/S架構的開發
在不同的計算機上, 一個安裝客戶端,一個安裝伺服器, 它們要通過網路來通訊
什麼是網路通訊呢 ?
利用網際網路來連線上,用來通訊
要完成通訊必須具備的條件 :
1. 物理連線介質 ( 網線, WIFI, 光纖)
2, 必須遵循相同的標準
在計算機網路中,同樣的需要具備這兩個條件.
作為一個應用軟體開發者, 不需要關心第一步, 我們的重點是通訊的標準,(通訊的協議)
網路協議 :
OSI 七層模型.: 後來由於覺得表示層跟會話層又麻煩又沒什麼用, 就把它兩個加入到了應用層.
應用層
表示層
會話層
傳輸層
網路層
資料鏈路層
物理層
物理層:
物理層的由來 :
上面提到,孤立的計算機之間要想一起玩, 就必須接入internet,言外之意就是
計算機之間必須完成組網
物理層的功能:
主要是基於電器特性發送高低電壓(電訊號),高電壓對應數字1. 低電壓對應數字0
資料鏈路層:
資料鏈路層的由來:
單純的電訊號0和1沒有任何意義,必須規定電訊號多少一位一組,每組什麼意思
資料鏈路層的功能:
定義了電訊號的分組方式
乙太網協議:
早期的時候各個公司都有自己的分組方式,後來形成了統一的標準,即乙太網協議ethernet
ethernet規定
-
-
- 一組電訊號構成一個數據報,叫做‘幀’
- 每一資料幀分成:報頭head和資料data兩部分
-
head包含:(固定18個位元組)
-
-
- 傳送者/源地址,6個位元組
- 接收者/目標地址,6個位元組
- 資料型別,6個位元組
-
data包含:(最短46位元組,最長1500位元組)
-
-
- 資料包的具體內容
-
head長度+data長度=最短64位元組,最長1518位元組,超過最大限制就分片傳送.
mac 地址:
head中包含的源和目標地址的由來 : ethernet規定接入internet 的裝置都必須具備網絡卡,傳送端
和接收端的地址便是指網絡卡的地址, 即mac地址
mac地址 : 每塊網絡卡出廠時都被燒製上一個世界唯一的mac地址, 長度為48位2進位制, 通常由12位
16進位制數表示(前六位是廠商編號,後六位是流水線號)
廣播:
有了mac地址, 同一網路內的兩臺主機就可以通訊了 (遺愛主機通過arp協議獲取另外一臺主機的
mac地址) ethernet採用最原始的方式, 廣播的方式進行通訊, 即計算機通訊基本靠吼.
如果大家都有自己的喇叭都想廣播,頻寬就承受不住了.
網路層會區分哪種人要廣播, 哪種不要廣播
乙太網協議 工作在資料鏈路層規定了, 資料報 (資料幀) 的格式, 乙太網協議傳輸資料的方式是廣播
然而在網路非常龐大的時候, 使用廣播的方式傳輸會造成資源的浪費, 造成網路癱瘓.
由於以上的問題, 推出了新的協議.
IP協議.
網路層:
網路層由來:
有了ethernet、mac地址、廣播的傳送方式,世界上的計算機就可以彼此通訊了,
問題是世界範圍的網際網路是由一個個彼此隔離的小的區域網組成的,
那麼如果所有的通訊都採用乙太網的廣播方式,那麼一臺機器傳送的包全世界都會收到,
這就不僅僅是效率低的問題了,這會是一種災難
網路層功能:
引入一套新的地址用來區分不同的廣播域 / 子網,這套地址即網路地址
IP協議:
-
-
- 規定網路地址的協議叫ip協議,它定義的地址稱之為ip地址,廣泛採用的v4版本即 ipv4,它規定網路地址由32位2進製表示
- 範圍0.0.0.0-255.255.255.255
- 一個ip地址通常寫成四段十進位制數,例:172.16.10.1
-
ip地址分成兩部分
-
-
- 網路部分:標識子網
- 主機部分:標識主機
-
注意:單純的ip地址段只是標識了ip地址的種類,從網路部分或主機部分都無法辨識
一個ip所處的子網.
例:172.16.10.1與172.16.10.2並不能確定二者處於同一子網
子網掩碼
所謂”子網掩碼”,就是表示子網路特徵的一個引數。它在形式上等同於IP地址,
也是一個32位二進位制數字,它的網路部分全部為1,主機部分全部為0。比如,
IP地址172.16.10.1,如果已知網路部分是前24位,主機部分是後8位,那麼子網路掩碼就是
11111111.11111111.11111111.00000000, 寫成十進位制就是255.255.255.0。
知道”子網掩碼”,我們就能判斷,任意兩個IP地址是否處在同一個子網路。
方法是將兩個IP地址與子網掩碼分別進行AND運算(兩個數位都為1,
運算結果為1,否則為0),然後比較結果是否相同,如果是的話,
就表明它們在同一個子網路中,否則就不是。
比如,已知IP地址172.16.10.1和172.16.10.2的子網掩碼都是255.255.255.0,
請問它們是否在同一個子網路?兩者與子網掩碼分別進行AND運算,
172.16.10.1:10101100.00010000.00001010.000000001
255255.255.255.0:11111111.11111111.11111111.00000000
AND運算得網路地址結果:10101100.00010000.00001010.000000001->172.16.10.0
172.16.10.2:10101100.00010000.00001010.000000010
255255.255.255.0:11111111.11111111.11111111.00000000
AND運算得網路地址結果:10101100.00010000.00001010.000000001->172.16.10.0
結果都是172.16.10.0,因此它們在同一個子網路。
總結一下,IP協議的作用主要有兩個,一個是為每一臺計算機分配IP地址,
另一個是確定哪些地址在同一個子網路。
ip資料包
ip資料包也分為head和data部分,無須為ip包定義單獨的欄位,直接放入乙太網包的data部分
head:長度為20到60位元組
data:最長為65,515位元組。
而乙太網資料包的”資料”部分,最長只有1500位元組。因此,如果IP資料包超過了1500位元組,
它就需要分割成幾個乙太網資料包,分開發送了。
ARP協議
arp協議由來:計算機通訊基本靠吼,即廣播的方式,所有上層的包到最後都要封裝上
乙太網頭,然後通過乙太網協議傳送,在談及乙太網協議時候,我門瞭解到
通訊是基於mac的廣播方式實現,計算機在發包時,獲取自身的mac是容易的,
如何獲取目標主機的mac,就需要通過arp協議
arp協議功能:廣播的方式傳送資料包,獲取目標主機的mac地址
協議工作方式:每臺主機ip都是已知的
例如:主機172.16.10.10/24訪問172.16.10.11/24
一:首先通過ip地址和子網掩碼區分出自己所處的子網
二:分析172.16.10.10/24與172.16.10.11/24處於同一網路(如果不是同一網路,
那麼下表中目標ip為172.16.10.1,通過arp獲取的是閘道器的mac)
三:這個包會以廣播的方式在傳送端所處的自網內傳輸,所有主機接收後拆開包,
發現目標ip為自己的,就響應,返回自己的mac