python進階(10)——單例/異常
單例
設計模式:前人留下的對某一特定問題的成熟的解決方案(套路)
單例設計模式:類建立的物件,在系統中只有唯一一個例項,每一次執行類名()返回的物件,記憶體地址是相同的
__new__方法:
使用類名()建立物件時,python直譯器執行兩步:
1首先呼叫__new__內建方法為物件分配空間,返回物件的引用(地址)
2呼叫__init__內建方法進行物件初始化
class MusicPlayer(object): pass # 建立多個物件 player1 = MusicPlayer() print(player1) player2 = MusicPlayer() print(player2)
<__main__.MusicPlayer object at 0x10126a4a8>
<__main__.MusicPlayer object at 0x10126a470>
輸出的兩個記憶體地址不一樣,說明player1和player2是兩個完全不同的物件
單例設計模式的目的就是無論建立多少次,物件的引用(地址)是相同的,怎麼解決?
定義一個類屬性instance,初始值是None,用於記錄物件的引用(初始時沒有值)
class MusicPlayer(object): # 定義類屬性,記錄第一個被建立物件的引用 instance = None def __new__(cls, *args, **kwargs): # 1 判斷類屬性是否是空物件 if cls.instance is None: # 2 呼叫父類的方法,為第一個物件分配空間 cls.instance = super().__new__(cls) # 3 返回類屬性儲存的物件引用 return cls.instance # 建立多個物件 player1 = MusicPlayer() print(player1) player2 = MusicPlayer() print(player2)
<__main__.MusicPlayer object at 0x1049c5438>
<__main__.MusicPlayer object at 0x1049c5438>
如果想要初始化動作只執行一次?
定義類屬性,判斷是否執行過初始化
class MusicPlayer(object): # 定義類屬性,記錄第一個被建立物件的引用 instance = None # 定義類屬性,記錄是否執行過初始化動作 init_flag = False def __new__(cls, *args, **kwargs): # 1 判斷類屬性是否是空物件 if cls.instance is None: # 2 呼叫父類的方法,為第一個物件分配空間 cls.instance = super().__new__(cls) # 3 返回類屬性儲存的物件引用 return cls.instance def __init__(self): # 1 判斷是否執行過初始化動作 if MusicPlayer.init_flag: return # 2 如果沒有執行過 print("初始化") # 3 修改類屬性的標記 MusicPlayer.init_flag = True # 建立多個物件 player1 = MusicPlayer() print(player1) player2 = MusicPlayer() print(player2)
異常
程式在執行時,遇到錯誤停止執行並提示一些錯誤資訊
通過異常捕獲,保證程式的健壯性
在程式的開發中,如果對某些程式碼的執行不確定是否正確,可以增加try來捕獲異常
格式:
try:
嘗試執行的程式碼
except:
出現錯誤的處理
try:
num = int(input("請輸入一個整數:"))
except:
print("請輸入正確的整數")
print("-" * 50)
請輸入一個整數:eee
請輸入正確的整數
--------------------------------------------------
異常型別捕獲演練:
輸入一個非零整數,進行除以8的操作,
錯誤型別:
try:
num = int(input("請輸入一個整數:"))
result = 8 / num
print(result)
except ZeroDivisionError:
print("除0錯誤")
except ValueError:
print("請輸入正確的整數")
以上捕獲的錯誤型別都是已知的錯誤,如果想對未知的錯誤進行捕獲?
可以再增加一個except
try:
num = int(input("請輸入一個整數:"))
result = 8 / num
print(result)
except ZeroDivisionError:
print("除0錯誤")
#假設輸入非整數時為未知錯誤
except Exception as result:
print("未知錯誤%s" % result)
請輸入一個整數:a
未知錯誤invalid literal for int() with base 10: 'a'
異常捕獲完整語法
try:
num = int(input("請輸入一個整數:"))
result = 8 / num
print(result)
except ZeroDivisionError:
print("除0錯誤")
except ValueError:
print("請輸入正確的整數")
except Exception as result:
print("未知錯誤%s" % result)
else:
print("嘗試成功")
finally:
print("無論是否出現錯誤都會執行的程式碼")
異常的傳遞:
把異常傳遞給函式或方法的呼叫方,程式不會被立刻終止
例:定義函式demo1()提示使用者輸入一個整數並返回;定義函式demo2()呼叫demo1();在主程式中使用demo2()
def demo1():
return int(input("輸入整數:"))
def demo2():
return demo1()
# 利用異常的傳遞性,在主程式捕獲異常
try:
print(demo2())
except Exception as result:
print("位置錯誤 %s" % result)
執行結果
輸入整數:a
位置錯誤 invalid literal for int() with base 10: 'a'
注:
在開發中,在主函式中新增異常捕獲
在主函式中呼叫的其他函式,只要出現異常,都會傳遞到主函式的異常捕獲中
這樣就不需要在程式碼中,增加大量的異常捕獲,能夠保證程式碼的整潔性
在實際開發中,除了程式碼出錯需要丟擲異常,還可以根據應用程式特有的業務需求主動丟擲異常:
1.建立exception異常物件
2.使用raise關鍵字丟擲異常物件
例,提示使用者輸入密碼,如果長度少於8,丟擲異常
def input_password():
# 1.輸入密碼
pwd = input("請輸入密碼")
# 2.判斷長度>=8,返回使用者輸入的密碼
if len(pwd) >= 8:
return
# 3.如果<8主動丟擲異常
print("主動丟擲異常")
ex = Exception("密碼長度不夠")
raise ex
try:
print(input_password())
except Exception as result:
print(result)