Python異常處理與反射相關問題總結

一、異常處理

在程序開發中如果遇到一些 不可預知的錯誤 或 你懶得做一些判斷 時,可以選擇用異常處理來做。

import requests
 
while True:
    url = input("請輸入要下載網頁地址:")
    res = requests.get(url=url)
    with open('content.txt', mode='wb') as f:
        f.write(res.content)

上述下載視頻的代碼在正常情況下可以運行,但如果遇到網絡出問題,那麼此時程序就會報錯無法正常執行

try:
    res = requests.get(url=url)
except Exception as e:
    代碼塊,上述代碼出異常待執行。
print("結束")
import requests
 
while True:
    url = input("請輸入要下載網頁地址:")
    
    try:
        res = requests.get(url=url)
    except Exception as e:
        print("請求失敗,原因:{}".format(str(e)))
        continue
        
    with open('content.txt', mode='wb') as f:
        f.write(res.content)
num1 = input("請輸入數字:")
num2 = input("請輸入數字:")
try:
    num1 = int(num1)
    num2 = int(num2)
    result = num1 + num2
    print(result)
except Exception as e:
    print("輸入錯誤")

以後常見的應用場景:

  • 調用微信的API實現微信消息的推送、微信支付等
  • 支付寶支付、視頻播放等
  • 數據庫 或 redis連接和操作
  • 調用第三方的視頻播放發的功能,由第三方的程序出問題導致的錯誤。

異常處理的基本格式:

try:
    # 邏輯代碼
except Exception as e:
    # try中的代碼如果有異常,則此代碼塊中的代碼會執行。
try:
    # 邏輯代碼
except Exception as e:
    # try中的代碼如果有異常,則此代碼塊中的代碼會執行。
finally:
    # try中的代碼無論是否報錯,finally中的代碼都會執行,一般用於釋放資源。
 
print("end")
 
"""
try:
    file_object = open("xxx.log")
    # ....
except Exception as e:
    # 異常處理
finally:
    file_object.close()  # try中沒異常,最後執行finally關閉文件;try有異常,執行except中的邏輯,最後再執行finally關閉文件。
"""

1.1 異常細分

import requests
 
while True:
    url = input("請輸入要下載網頁地址:")
    
    try:
        res = requests.get(url=url)
    except Exception as e:
        print("請求失敗,原因:{}".format(str(e)))
        continue
        
    with open('content.txt', mode='wb') as f:
        f.write(res.content)

之前隻是簡單的捕獲瞭異常,出現異常則統一提示信息即可。如果想要對異常進行更加細致的異常處理,則可以這樣來做:

import requests
from requests import exceptions
 
while True:
    url = input("請輸入要下載網頁地址:")
    try:
        res = requests.get(url=url)
        print(res)    
    except exceptions.MissingSchema as e:
        print("URL架構不存在")
    except exceptions.InvalidSchema as e:
        print("URL架構錯誤")
    except exceptions.InvalidURL as e:
        print("URL地址格式錯誤")
    except exceptions.ConnectionError as e:
        print("網絡連接錯誤")
    except Exception as e:
        print("代碼出現錯誤", e)
        
# 提示:如果想要寫的簡單一點,其實隻寫一個Exception捕獲錯誤就可以瞭

如果想要對錯誤進行細分的處理,例如:發生Key錯誤和發生Value錯誤分開處理。

try:
    # 邏輯代碼
    pass
 
except KeyError as e:
    # 小兵,隻捕獲try代碼中發現瞭鍵不存在的異常,例如:去字典 info_dict["n1"] 中獲取數據時,鍵不存在。
    print("KeyError")
 
except ValueError as e:
    # 小兵,隻捕獲try代碼中發現瞭值相關錯誤,例如:把字符串轉整型 int("無誒器")
    print("ValueError")
 
except Exception as e:
    # 王者,處理上面except捕獲不瞭的錯誤(可以捕獲所有的錯誤)。
    print("Exception")

Python中內置瞭很多細分的錯誤,供你選擇。

常見異常:
“””
AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x
IOError 輸入/輸出異常;基本上是無法打開文件
ImportError 無法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError 下標索引超出序列邊界,比如當x隻有三個元素,卻試圖訪問n x[5]
KeyError 試圖訪問字典裡不存在的鍵 inf[‘xx’]
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,代碼不能編譯(個人認為這是語法錯誤,寫錯瞭)
TypeError 傳入對象類型與要求的不符合
UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量,
導致你以為正在訪問它
ValueError 傳入一個調用者不期望的值,即使值的類型是正確的
“””
更多異常:
“””
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
“””

1.2 自定義異常&拋出異常

上面都是Python內置的異常,隻有遇到特定的錯誤之後才會拋出相應的異常。

其實,在開發中也可以自定義異常。

class MyException(Exception):
    pass
try:
    pass
except MyException as e:
    print("MyException異常被觸發瞭", e)
except Exception as e:
    print("Exception", e)

上述代碼在except中定義瞭捕獲MyException異常,但他永遠不會被觸發。因為默認的那些異常都有特定的觸發條件,例如:索引不存在、鍵不存在會觸發IndexError和KeyError異常。

對於我們自定義的異常,如果想要觸發,則需要使用:raise MyException()類實現。

class MyException(Exception):
    pass
 
 
try:
    # 。。。
    raise MyException()
    # 。。。
except MyException as e:
    print("MyException異常被觸發瞭", e)
except Exception as e:
    print("Exception", e)
class MyException(Exception):
    def __init__(self, msg, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.msg = msg
 
 
try:
    raise MyException("xxx失敗瞭")
except MyException as e:
    print("MyException異常被觸發瞭", e.msg)
except Exception as e:
    print("Exception", e)
class MyException(Exception):
    title = "請求錯誤"
 
 
try:
    raise MyException()
except MyException as e:
    print("MyException異常被觸發瞭", e.title)
except Exception as e:
    print("Exception", e)

案例一:你我合作協同開發,你調用我寫的方法。

我定義瞭一個函數

class EmailValidError(Exception):
    title = "郵箱格式錯誤"
 
class ContentRequiredError(Exception):
    title = "文本不能為空錯誤"
    
def send_email(email,content):
    if not re.match("\[email protected]",email):
        raise EmailValidError()
	if len(content) == 0 :
        raise ContentRequiredError()
	# 發送郵件代碼...
    # ...

你調用我寫的函數

def execute():
    # 其他代碼
    # ...
    
	try:
        send_email(...)
    except EmailValidError as e:
        pass
    except ContentRequiredError as e:
        pass
    except Exception as e:
        print("發送失敗")
 
execute()
 
# 提示:如果想要寫的簡單一點,其實隻寫一個Exception捕獲錯誤就可以瞭。

案例二:在框架內部已經定義好,遇到什麼樣的錯誤都會觸發不同的異常。

import requests
from requests import exceptions
 
while True:
    url = input("請輸入要下載網頁地址:")
    try:
        res = requests.get(url=url)
        print(res)    
    except exceptions.MissingSchema as e:
        print("URL架構不存在")
    except exceptions.InvalidSchema as e:
        print("URL架構錯誤")
    except exceptions.InvalidURL as e:
        print("URL地址格式錯誤")
    except exceptions.ConnectionError as e:
        print("網絡連接錯誤")
    except Exception as e:
        print("代碼出現錯誤", e)
        
# 提示:如果想要寫的簡單一點,其實隻寫一個Exception捕獲錯誤就可以瞭。

案例三:按照規定去觸發指定的異常,每種異常都具備被特殊的含義。

1.4 特殊的finally

try:
    # 邏輯代碼
except Exception as e:
    # try中的代碼如果有異常,則此代碼塊中的代碼會執行。
finally:
    # try中的代碼無論是否報錯,finally中的代碼都會執行,一般用於釋放資源。
 
print("end")

當在函數或方法中定義異常處理的代碼時,要特別註意finally和return

def func():
    try:
        return 123
    except Exception as e:
        pass
    finally:
        print(666)
        
func()

在try或except中即使定義瞭return,也會執行最後的finally塊中的代碼。

二、反射

反射,提供瞭一種更加靈活的方式讓你可以實現去 對象 中操作成員(以字符串的形式去 對象 中進行成員的操作)。

class Person(object):
    
    def __init__(self,name,wx):
        self.name = name
        self.wx = wx
	
    def show(self):
        message = "姓名{},微信:{}".format(self.name,self.wx)
        
        
user_object = Person("華青水上","hqss666")
 
 
# 對象.成員 的格式去獲取數據
user_object.name
user_object.wx
user_object.show()
 
# 對象.成員 的格式無設置數據
user_object.name = "華青水上"
user = Person("華青水上","hqss666")
 
# getattr 獲取成員
getattr(user,"name") # user.name
getattr(user,"wx")   # user.wx
 
 
method = getattr(user,"show") # user.show
method()
# 或
getattr(user,"show")()
 
# setattr 設置成員
setattr(user, "name", "華青水上") # user.name = "華青水上"

Python中提供瞭4個內置函數來支持反射:

getattr,去對象中獲取成員

v1 = getattr(對象,"成員名稱")
v2 = getattr(對象,"成員名稱", 不存在時的默認值)

setattr,去對象中設置成員

setattr(對象,"成員名稱",值)

hasattr,對象中是否包含成員

v1 = hasattr(對象,"成員名稱") # True/False

delattr,刪除對象中的成員

delattr(對象,"成員名稱")

以後如果再遇到 對象.成員 這種編寫方式時,均可以基於反射來實現。

class Account(object):
 
    def login(self):
        pass
 
    def register(self):
        pass
 
    def index(self):
        pass
 
    
def run(self):
    name = input("請輸入要執行的方法名稱:") # index register login xx run ..
    
    account_object = Account()
    method = getattr(account_object, name,None) # index = getattr(account_object,"index")
    
    if not method:
        print("輸入錯誤")
        return 
    method()

2.1 一些皆對象

在Python中有這麼句話:一切皆對象。 每個對象的內部都有自己維護的成員。

對象是對象

class Person(object):
    
    def __init__(self,name,wx):
        self.name = name
        self.wx = wx
	
    def show(self):
        message = "姓名{},微信:{}".format(self.name,self.wx)
        
        
user_object = Person("華青水上","hqss666")
user_object.name

類是對象

class Person(object):
    title = "武沛齊"
 
Person.title
# Person類也是一個對象(平時不這麼稱呼)

模塊是對象

import re
 
re.match
# re模塊也是一個對象(平時不這麼稱呼)。

由於反射支持以字符串的形式去對象中操作成員【等價於 對象.成員 】,所以,基於反射也可以對類、模塊中的成員進行操作。

簡單粗暴:隻要看到 xx.oo 都可以用反射實現。

class Person(object):
    title = "華青水上"
 
v1 = Person.title
print(v1)
v2 = getattr(Person,"title")
print(v2)
import re
 
v1 = re.match("\w+","dfjksdufjksd")
print(v1)
 
func = getattr(re,"match")
v2 = func("\w+","dfjksdufjksd")
print(v2)

2.2 import_module + 反射

# 導入模塊
from importlib import import_module
 
m = import_module("random")
 
v1 = m.randint(1,100)

在Python中如果想要導入一個模塊,可以通過import語法導入;企業也可以通過字符串的形式導入。

示例一:

# 導入模塊
import random
 
v1 = random.randint(1,100)

示例二:

# 導入模塊exceptions
from requests import exceptions as m
# 導入模塊exceptions
from importlib import import_module
m = import_module("requests.exceptions")

示例三:

# 導入模塊exceptions,獲取exceptions中的InvalidURL類。
from requests.exceptions import InvalidURL
# 錯誤方式
from importlib import import_module
m = import_module("requests.exceptions.InvalidURL") # 報錯,import_module隻能導入到模塊級別
# 導入模塊
from importlib import import_module
m = import_module("requests.exceptions")
# 去模塊中獲取類
cls = m.InvalidURL

在很多項目的源碼中都會有 import_modulegetattr 配合實現根據字符串的形式導入模塊並獲取成員,例如:

from importlib import import_module
 
path = "openpyxl.utils.exceptions.InvalidFileException"
 
module_path,class_name = path.rsplit(".",maxsplit=1) # "openpyxl.utils.exceptions"   "InvalidFileException"
 
module_object = import_module(module_path)
 
cls = getattr(module_object,class_name)
 
print(cls)

我們在開發中也可以基於這個來進行開發,提高代碼的可擴展性。

至此Python進階中面向對象之異常處理與反射總結完畢,如有不當之處,歡迎指正!

到此這篇關於Python異常處理與反射相關問題總結的文章就介紹到這瞭,更多相關Python異常處理與反射內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: