一、分支結構
分支結構是根據不同的判斷結果,而選擇不同的程序路徑的運行方式。
1.1 單分支結構
//若條件爲if True
則會直接執行語句塊。
1.2 二分支結構
示例一:
guess = eval(input("請輸入一個數:"))
if guess == 99:
print("猜對了")
else:
print("猜錯了")
示例二:
if True:
print("猜對了") ##這裏並不會執行到`else:`後面的語句。
else:
print("猜錯了")
二分支結構的緊湊形式
結構 <表達式1>if<條件>else<表達式2>
表達式1:表示當條件成立時執行表達式一。
if <條件>:指的是判斷條件。
<表達式2>:指的是條件不成立執行表達式2
guess = eval(input("請輸入一個數:"))
print("猜{}了".format("對"if guess == 99 else "錯"))
#將“對”與“錯”設爲表達式
### 這裏if與else所帶的是表達式而不*是語句,簡單理解語句是要帶賦值形式的,這裏只能提供只用表達式
1.3 多分支結構
二、程序的異常處理
調試Python程序時,經常會報出一些異常,異常的原因一方面可能是寫程序時由於疏忽或者考慮不全造成了錯誤,這時就需要根據異常Traceback到出錯點,進行分析改正;另一方面,有些異常是不可避免的,但我們可以對異常進行捕獲處理,防止程序終止
2.1 異常的類型
Python的異常處理能力是很強大的,它有很多內置異常,可向用戶準確反饋出錯信息。在Python中,異常也是對象,可對它進行操作。BaseException是所有內置異常的基類,但用戶定義的類並不直接繼承BaseException,所有的異常類都是從Exception繼承,且都在exceptions模塊中定義。Python自動將所有異常名稱放在內建命名空間中,所以程序不必導入exceptions模塊即可使用異常。一旦引發而且沒有捕捉SystemExit異常,程序執行就會終止。如果交互式會話遇到一個未被捕捉的SystemExit異常,會話就會終止。
代碼:
num = eval(input("請輸入一個數:"))
num = num ** 2
輸入:a
執行結果:
Traceback (most recent call last):
File "E:/python練習/python練習實例/time庫的使用/1.py", line 8, in <module>
num = eval(input("請輸入一個數:"))
File "<string>", line 1, in <module>
NameError: name 'a' is not defined
內置異常類的層次結構如下:
BaseException # 所有異常的基類
+-- SystemExit # 解釋器請求退出
+-- KeyboardInterrupt # 用戶中斷執行(通常是輸入^C)
+-- GeneratorExit # 生成器(generator)發生異常來通知退出
+-- Exception # 常規異常的基類
+-- StopIteration # 迭代器沒有更多的值
+-- StopAsyncIteration # 必須通過異步迭代器對象的__anext__()方法引發以停止迭代
+-- ArithmeticError # 各種算術錯誤引發的內置異常的基類
| +-- FloatingPointError # 浮點計算錯誤
| +-- OverflowError # 數值運算結果太大無法表示
| +-- ZeroDivisionError # 除(或取模)零 (所有數據類型)
+-- AssertionError # 當assert語句失敗時引發
+-- AttributeError # 屬性引用或賦值失敗
+-- BufferError # 無法執行與緩衝區相關的操作時引發
+-- EOFError # 當input()函數在沒有讀取任何數據的情況下達到文件結束條件(EOF)時引發
+-- ImportError # 導入模塊/對象失敗
| +-- ModuleNotFoundError # 無法找到模塊或在在sys.modules中找到None
+-- LookupError # 映射或序列上使用的鍵或索引無效時引發的異常的基類
| +-- IndexError # 序列中沒有此索引(index)
| +-- KeyError # 映射中沒有這個鍵
+-- MemoryError # 內存溢出錯誤(對於Python 解釋器不是致命的)
+-- NameError # 未聲明/初始化對象 (沒有屬性)
| +-- UnboundLocalError # 訪問未初始化的本地變量
+-- OSError # 操作系統錯誤,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合併到OSError中,構造函數可能返回子類
| +-- BlockingIOError # 操作將阻塞對象(e.g. socket)設置爲非阻塞操作
| +-- ChildProcessError # 在子進程上的操作失敗
| +-- ConnectionError # 與連接相關的異常的基類
| | +-- BrokenPipeError # 另一端關閉時嘗試寫入管道或試圖在已關閉寫入的套接字上寫入
| | +-- ConnectionAbortedError # 連接嘗試被對等方中止
| | +-- ConnectionRefusedError # 連接嘗試被對等方拒絕
| | +-- ConnectionResetError # 連接由對等方重置
| +-- FileExistsError # 創建已存在的文件或目錄
| +-- FileNotFoundError # 請求不存在的文件或目錄
| +-- InterruptedError # 系統調用被輸入信號中斷
| +-- IsADirectoryError # 在目錄上請求文件操作(例如 os.remove())
| +-- NotADirectoryError # 在不是目錄的事物上請求目錄操作(例如 os.listdir())
| +-- PermissionError # 嘗試在沒有足夠訪問權限的情況下運行操作
| +-- ProcessLookupError # 給定進程不存在
| +-- TimeoutError # 系統函數在系統級別超時
+-- ReferenceError # weakref.proxy()函數創建的弱引用試圖訪問已經垃圾回收了的對象
+-- RuntimeError # 在檢測到不屬於任何其他類別的錯誤時觸發
| +-- NotImplementedError # 在用戶定義的基類中,抽象方法要求派生類重寫該方法或者正在開發的類指示仍然需要添加實際實現
| +-- RecursionError # 解釋器檢測到超出最大遞歸深度
+-- SyntaxError # Python 語法錯誤
| +-- IndentationError # 縮進錯誤
| +-- TabError # Tab和空格混用
+-- SystemError # 解釋器發現內部錯誤
+-- TypeError # 操作或函數應用於不適當類型的對象
+-- ValueError # 操作或函數接收到具有正確類型但值不合適的參數
| +-- UnicodeError # 發生與Unicode相關的編碼或解碼錯誤
| +-- UnicodeDecodeError # Unicode解碼錯誤
| +-- UnicodeEncodeError # Unicode編碼錯誤
| +-- UnicodeTranslateError # Unicode轉碼錯誤
+-- Warning # 警告的基類
+-- DeprecationWarning # 有關已棄用功能的警告的基類
+-- PendingDeprecationWarning # 有關不推薦使用功能的警告的基類
+-- RuntimeWarning # 有關可疑的運行時行爲的警告的基類
+-- SyntaxWarning # 關於可疑語法警告的基類
+-- UserWarning # 用戶代碼生成警告的基類
+-- FutureWarning # 有關已棄用功能的警告的基類
+-- ImportWarning # 關於模塊導入時可能出錯的警告的基類
+-- UnicodeWarning # 與Unicode相關的警告的基類
+-- BytesWarning # 與bytes和bytearray相關的警告的基類
+-- ResourceWarning # 與資源使用相關的警告的基類。被默認警告過濾器忽略。
2.2 異常捕獲
當發生異常時,程序會自動中斷或退出,這對用戶體驗與程序執行無疑很不爽,我們就需要對異常進行捕獲,然後進行相應的處理。python的異常捕獲常用try...except...
結構,把可能發生錯誤的語句放在try模塊裏,用except來處理異常,每一個try,都必須至少對應一個except。
異常處理的基本使用
我們把要執行的語句放在try:
模塊中,如果語句執行錯誤,則執行expect:
模塊後的<語句塊2>
,反之<語句塊1>
執行正確,則跳過except
模塊繼續執行後面的其他語句。同時我們也可以應用<異常類型>
對不通的異常做相應的處理。
示例一:
代碼:
try:
num = eval(input("請輸入一個數:"))
num = num ** 2
except:
print("輸入錯誤")
## 此時輸入值錯誤,會直接返回輸入錯誤。
示例二:
try:
num = eval(input("請輸入一個數:"))
num = num ** 2
except NameError: ## 這裏標註類型異常會,僅響應該類型異常,其他類型的不響應,NameError相當於一個變量,這裏python中自己已經定義了。
print("輸入錯誤")
萬能異常:
try:
<語句>
except Exception:
print('異常說明')
捕獲多個異常
捕獲多個異常有兩種方式,第一種是一個except同時處理多個異常,不區分優先級:
try:
<語句>
except (<異常名1>, <異常名2>, ...):
print('異常說明')
第二種是區分優先級的:
try:
<語句>
except <異常名1>:
print('異常說明1')
except <異常名2>:
print('異常說明2')
except <異常名3>:
print('異常說明3')
該種異常處理語法的規則是:
執行try下的語句,如果引發異常,則執行過程會跳到第一個except語句。
如果第一個except中定義的異常與引發的異常匹配,則執行該except中的語句。
如果引發的異常不匹配第一個except,則會搜索第二個except,允許編寫的except數量沒有限制。
如果所有的except都不匹配,則異常會傳遞到下一個調用本代碼的最高層try代碼中。
此外,與python異常相關的關鍵字主要有:
關鍵字 | 關鍵字說明 |
---|---|
try/except | 捕獲異常並處理 |
pass | 忽略異常 |
as | 定義異常實例(except MyError as e) |
else | 如果try中的語句沒有引發異常,則執行else中的語句 |
finally | 無論是否出現異常,都執行的代碼 |
raise | 拋出/引發異常 |
else
如果判斷完沒有某些異常之後還想做其他事,就可以使用下面這樣的else語句。
try:
<語句>
except <異常名1>:
print('異常說明1')
except <異常名2>:
print('異常說明2')
else:
<語句> # try語句中沒有異常則執行此段代碼
finally
try…finally…語句無論是否發生異常都將會執行最後的代碼。
try:
<語句>
finally:
<語句>
看一個示例:
代碼:
str1 = 'hello world'
try:
int(str1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
else:
print('try內沒有異常')
finally:
print('無論異常與否,都會執行我')
執行結果:
invalid literal for int() with base 10: 'hello world'
無論異常與否,都會執行我
raise主動觸發異常
可以使用raise語句自己觸發異常,raise語法格式如下:
raise [Exception [, args [, traceback]]]
語句中Exception是異常的類型(例如ValueError),參數是一個異常參數值。該參數是可選的,如果不提供,異常的參數是"None"。最後一個參數是跟蹤異常對象,也是可選的(在實踐中很少使用)。
示例:
代碼:
def not_zero(num):
try:
if num == 0:
raise ValueError('參數錯誤')
return num
except Exception as e:
print(e)
not_zero(0)
執行結果:
參數錯誤
2.3 採用traceback模塊查看異常
發生異常時,Python能“記住”引發的異常以及程序的當前狀態。Python還維護着traceback(跟蹤)對象,其中含有異常發生時與函數調用堆棧有關的信息。記住,異常可能在一系列嵌套較深的函數調用中引發。程序調用每個函數時,Python會在“函數調用堆棧”的起始處插入函數名。一旦異常被引發,Python會搜索一個相應的異常處理程序。如果當前函數中沒有異常處理程序,當前函數會終止執行,Python會搜索當前函數的調用函數,並以此類推,直到發現匹配的異常處理程序,或者Python抵達主程序爲止。這一查找合適的異常處理程序的過程就稱爲“堆棧輾轉開解”(StackUnwinding)。解釋器一方面維護着與放置堆棧中的函數有關的信息,另一方面也維護着與已從堆棧中“輾轉開解”的函數有關的信息。
格式如下:
try:
block
except:
traceback.print_exc()
示例:
try:
1/0
except Exception as e:
print(e)
如果我們這樣寫的話,程序只會報“division by zero”錯誤,但是我們並不知道是在哪個文件哪個函數哪一行出的錯。
下面使用traceback模塊,官方參考文檔:https://docs.python.org/2/library/traceback.html
import traceback
try:
1/0
except Exception as e:
traceback.print_exc()
這樣就會幫我們追溯到出錯點:
Traceback (most recent call last):
File "E:/PycharmProjects/ProxyPool-master/proxypool/test.py", line 4, in <module>
1/0
ZeroDivisionError: division by zero
另外,traceback.print_exc()跟traceback.format_exc()有什麼區別呢?
區別就是,format_exc()返回字符串,print_exc()則直接給打印出來。即traceback.print_exc()與print(traceback.format_exc())效果是一樣的。print_exc()還可以接受file參數直接寫入到一個文件。比如可以像下面這樣把相關信息寫入到tb.txt文件去。
traceback.print_exc(file=open('tb.txt','w+'))