異常(高級) Exception
異常回顧:
try-except 語句 捕獲(接收)異常通知,把異常流程變為正常流程
try-finally 語句 執行必須要執行的語句.
raise 語句 發送異常通知,同時進入異常流程
assert 語句 發送AssertionError異常
with 語句
with語句
語法:
with 表達式1 [as 變量1], 表達式2 [as 變量2], ...:
語句塊
作用:
使用於對資源進行訪問的場合,確保使用過程中不管是否發生異常都會執行必要的清理操作,並釋放資源
如: 文件使用后自動關閉,線程中鎖的自動獲取和釋放等

try: # file = open("../day19.txt") with open('../day19.txt') as file: line1 = file.readline() print("第一行內容是:", line1) n = int(line1) # with語句保證在出異時,文件也能被關閉 print(n) except OSError: print("文件打開失敗") except ValueError: print('讀寫文件時出錯')
說明:
with語句同try-finally語句一樣,不會改變程序的狀態(異常或正常狀態)
環境管理器:
類內有'__enter__' 和 '__exit__' 實例方法的類被稱為環境管理器能夠用with語句進行管理的對象必須是環境管理器
__enter__將在進入with語句之前被調用,並返回由as 變量管理的對象
__exit__ 將在離開with語句時被調用,且可以用參數來判斷在離開with語句時是否有異常發生並做出相應的處理

class A: def __enter__(self): print("__enter__方法被調用") # 此處打開文件 return self # self 將被with as后的變量綁定 def __exit__(self, exc_type, exc_val, exc_tb): print("__exit__方法被調用") # 此處關閉文件 if exc_type is None: print("正常離開with語句") else: print("異常離開with語句") print(exc_type, exc_val, exc_tb) try: with A() as a: print("這是with內的語句") err = ValueError("故意拋出一個錯誤") raise err except ValueError: print("with語句內出現異常!!")
異常類:
BaseExcetion 類是一切異常類的基類
自定義的異常類型必須直接或間接的繼承自BaseExcetion類
運算符重載
讓自定義的類生成的對象(實例) 能夠使用運算符進行操作
作用:
讓自定義類的實例像內建對象一樣進行運算符操作
讓程序簡潔易讀
對自定義對象將運算符賦予新的運算規則
說明:
運算符已經有固定的含義,不建議改變原有運算符的含義
方法名 運算符和表達式 說明
__add__(self, rhs) self + rhs 加法
__sub__(self, rhs) self - rhs 減法
__mul__(self, rhs) self * rhs 乘法
__truediv__(self, rhs) self / rhs 除法
__floordiv__(self, rhs) self // rhs 地板除法
__mod__(self, rhs) self % rhs 求余
__pow__(self, rhs) self ** rhs 冪運算
rhs (right hand side) 右手邊
二元運算符的重載方法:
def __xxx__(self, other):
...

class MyNumber: def __init__(self, value): self.data = value def __repr__(self): return "MyNumber(%d)" % self.data def __add__(self, other): temp = self.data + other.data obj = MyNumber(temp) # 創建一個新的對象 return obj def __sub__(self, other): temp = self.data - other.data obj = MyNumber(temp) # 創建一個新的對象 return obj n1 = MyNumber(100) n2 = MyNumber(200) # n3 = n1.__add__(n2) n3 = n1 + n2 # 等同於 n3 = n1.__add__(n2) print(n1, "+", n2, '=', n3) n4 = n1 - n2 print(n1, "-", n2, '=', n4)
反向算術運算符的重載
當運算符的左側為內建類型時,右側為自定義類的對象進行算術運算符運算時,會出現TypeError錯誤,因無法修改內建類型的代碼來實現運算符重載,此時需要反向算術運算符重載
方法如下:
方法名 運算符和表達式 說明
__radd__(self, lhs) lhs + self 加法
__rsub__(self, lhs) lhs + self 減法
__rmul__(self, lhs) lhs * self 乘法
__rtruediv__(self, lhs) lhs / self 除法
__rfloordiv__(self, lhs) lhs // self 地板除法
__rmod__(self, lhs) lhs % self 求余
__rpow__(self, lhs) lhs ** self 冪運算
lhs (left hand side) 左手邊

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __add__(self, rhs): L = self.data + rhs.data return MyList(L) def __repr__(self): return "MyList(%s)" % self.data def __mul__(self, rhs): L = self.data * rhs return MyList(L) def __rmul__(self, lhs): print("__rmul__被調用") return MyList(self.data * lhs) L1 = MyList(range(1, 4)) L2 = MyList([4, 5, 6]) L5 = L1 * 2 # L5 = L1.__mul__(2) print(L5) # MyList([1, 2, 3, 1, 2, 3]) L6 = 2 * L1 # L1.__rmul__(2) 2.__mul__(L1) print(L6) # ???
復合賦值算術運算符的重載
以復合賦值算述運算符 x += y 主為例,此運算符會優先調用x.__iadd__(y) ,如果沒有__iadd__方法時,會將復合賦值運算符拆解為 x = x + y然后調用x = x.__add__(y)方法,如再不存在__add__方法,則會觸發TypeError錯誤
其它復合賦值運算符有相同的規則
方法名 運算符和表達式 說明
__iadd__(self, rhs) self += rhs 加法
__isub__(self, rhs) self -= rhs 減法
__imul__(self, rhs) self *= rhs 乘法
__itruediv__(self, rhs) self /= rhs 除法
__ifloordiv__(self, rhs) self //= rhs 地板除法
__imod__(self, rhs) self %= rhs 求余
__ipow__(self, rhs) self **= rhs 冪運算
rhs (right hand side) 右手邊

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr__(self): return "MyList(%s)" % self.data def __add__(self, rhs): print("__add__") L = self.data + rhs.data return MyList(L) # def __iadd__(self, rhs): # print("__iadd__") # self.data += rhs.data # return self L1 = MyList(range(1, 4)) L2 = MyList([4, 5, 6]) print("+= 之前的 id(L1)", id(L1)) L3 = L1 L1 += L2 print("+= 之后的 id(L1)", id(L1)) print(L1) print(L3)
比較運算符的重載
方法名 運算符和表達式 說明
__lt__(self, rhs) self < rhs 小於
__le__(self, rhs) self <= rhs 小於等於
__gt__(self, rhs) self > rhs 大於
__ge__(self, rhs) self >= rhs 大於等於
__eq__(self, rhs) self == rhs 等於
__ne__(self, rhs) self != rhs 不等於
注: 比較運算符通常返回布爾值 True 或 False
位運算符的重載
方法名 運算符和表達式 說明
__and__(self, rhs) self & rhs 位與
__or__(self, rhs) self | rhs 位或
__xor__(self, rhs) self ^ rhs 位異與
__lshift__(self, rhs) self << rhs 左移
__rshift__(self, rhs) self >> rhs 右移
反向位運算符的重載
方法名 運算符和表達式 說明
__rand__(self, lhs) lhs & self 位與
__ror__(self, lhs) lhs | self 位或
__rxor__(self, lhs) lhs ^ self 位異與
__rlshift__(self, lhs) lhs << self 左移
__rrshift__(self, lhs) lhs >> self 右移
復合賦值位運算符的重載
方法名 運算符和表達式 說明
__iand__(self, rhs) self &= rhs 位與
__ior__(self, rhs) self |= rhs 位或
__ixor__(self, rhs) self ^= rhs 位異與
__ilshift__(self, rhs) self <<= rhs 左移
__irshift__(self, rhs) self >>= rhs 右移
一元運算符的重載
方法名 運算符和表達式 說明
__neg__(self) -self 負號
__pos__(self) +self 正號
__invert__(self) ~self 取反
一元運算符的重載語法:
class 類名:
def __xxx__(self):
...

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr__(self): return "MyList(%s)" % self.data def __neg__(self): return MyList([-x for x in self.data]) L1 = MyList([1, -2, 3, -4, 5]) L2 = -L1 print(L2) # MyList([-1, 2, -3, 4, -5])
in , not in 運算符的重載
方法名 運算符和表達式 說明
__contains__(self, e) e in self 成員運算

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr__(self): return "MyList(%s)" % self.data def __contains__(self, item): return item in self.data L1 = MyList([1, -2, 3, -4, 5]) if 3 in L1: print("真") else: print("假") print(3 not in L1)
索引和切片運算符的重載:
重載方法
方法名 運算符和表達式 說明
__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self, i, v) self[i] = v 索引/切片賦值
__delitem__(self, i) del self[i] 刪除索引/切片
作用:
讓自定義的類型的對象能夠支持索引和切片操作

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr__(self): return "MyList(%s)" % self.data def __getitem__(self, item): print("__getitem__", item) return self.data[item] def __setitem__(self, key, value): print("__setitem__(key=", key, ',value=', value,')') self.data[key] = value def __delitem__(self, key): print('正在刪除第', key, '個元素') L1 = MyList([1, -2, 3, -4, 5]) v = L1[2] # 調用 v = L1.__getitem__(2) print(v) # 3 L1[1] = 2 # 調用 L1.__setitem__(1, 2) print(L1) del L1[3] # 調用 L1.__delitem__(3)

class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr__(self): return "MyList(%s)" % self.data def __getitem__(self, item): print("__getitem__:", item) if type(item) is int: print("正在做索引操作,item=", item) elif type(item) is slice: print("正在做切片操作:") print("起始值:", item.start) print("終止值:", item.stop) print("步長:", item.step) return self.data[item] L1 = MyList([1, -2, 3, -4, 5]) v = L1[1::2] print(v) v = L1[3] print(v) # L1[1:2:3] = [4, 5, 6] # L1.__setitem__(slice(1, 2, 3), [4, 5, 6])
slice 構造函數
作用:
用於創建一個slice切片對象,此對象存儲一個切片的起始值,終止值,步長信息
格式:
slice(start=None, stop=None, step=None)
slice對象的實例屬性
s.start 切片的起始值,默認為None
s.stop 切片的終止值,默認為None
s.step 切片的步長,默認為None
特性屬性 @property
實現其它語言所擁有的getter 和 setter功能
作用:
用來模擬一個屬性
通過@property裝飾器可以對模擬屬性賦值和取值加以控制

class Student: def __init__(self, s): self.__score = s # 成績 @property def score(self): '''getter''' return self.__score @score.setter def score(self, new_score): '''setter''' assert 0 <= new_score <= 100, '成績不合法' self.__score = new_score s1 = Student(50) print(s1.score) s1.score = 999 # 用setter來控制賦值操作 print(s1.score)