(D20)Python-異常高階,運算子過載
異常(高階)
異常相關的語句:
- try-except
- try-finally
- raise 觸發異常,發生錯誤通知
- assert 根據條件觸發AssertionError型別的錯誤通知
with 語句
with語句
- 語法:
- with 表示式1[as 變數1], 表示式2 [as 變數2], …:
- 語句塊
- with 表示式1[as 變數1], 表示式2 [as 變數2], …:
- 作用:
- 使用於對資源進行訪問的場合,確保使用過程中不管是否發生異常,都會執行必須的’清理’操作,並釋放資源
- 如: 檔案使用後自動關閉,執行緒中鎖的自動獲取和釋放等
- 說明:
- 執行表示式用as子句中的變數繫結生成的物件
- with 語句並不改變異常的的狀態
示例
src_file = input("請輸入原始檔: ") try: src = open(src_file, 'rb') try: try: # 準備開啟別一個檔案 dst_file = input("請輸入目標檔案: ") dst = open(dst_file, 'wb') try: # 開始讀寫檔案 b = src.read() dst.write(b) finally: # 關閉檔案 dst.close() except OSError: print('開啟寫檔案失敗') finally: src.close() except OSError: print("開啟檔案", src_file, '失敗')
示例
src_file = input("請輸入原始檔: ") dst_file = input("請輸入目標檔案: ") try: with open(src_file, 'rb') as src: # 準備開啟別一個檔案 with open(dst_file, 'wb') as dst: # 開始讀寫檔案 b = src.read() dst.write(b) except OSError: print("複製失敗") src_file = input("請輸入原始檔: ") dst_file = input("請輸入目標檔案: ") try: with open(src_file, 'rb') as src, \ open(dst_file, 'wb') as dst: b = src.read() dst.write(b) except OSError: print("複製失敗")
環境管理器(也有叫上下文管理器)
- 1.類內有__enter__方法和__exit__例項方法的類被稱為環境管理器
- 2.能夠用with語句進行管理的物件必須是環境管理器
- 3.__enter__將在進入with語句時被呼叫,並返回由 as 變數繫結的物件
- 4.__exit__將在離開with語句時被呼叫,且可以用引數來判斷在離開with語句時是否有異常發生並做出相應的處理
示例
class A:
'''此類的物件可以用於with語句進行管理'''
def __enter__(self):
print("已經進入with語句")
return self
def __exit__(self, exc_type, exc_value, exc_tb):
print("已經離開了with語句")
if exc_type is None:
print("在with語句內部沒有發生異常,正常離開with")
else:
print("離開with語句時出現異常")
print("異常型別是:", exc_type)
print("錯誤的值是:", exc_value)
try:
with A() as a:
print("這是with語句裡列印的")
3 / 0 # 觸發異常
except:
print("有異常發生,程式已轉為正常!")
print("程式退出")
運算子過載
- 什麼是運算子過載:
- 讓自定義的類生成的物件(例項)能夠例項運算子進行操作
- 作用:
- 讓自定義類的例項像內建物件一樣進行運算子操作
- 讓程式簡潔易讀
- 對自定義的物件將運算子賦予新的運算規則
- 說明:
- 運算子過載方法的引數已經有固定的含義,不建議改變原有的意義
算術運算過載
方法名 運算子和表示式 說明
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 hands side)
示例
class MyNumber:
def __init__(self, v):
self.data = v
def __repr__(self):
return "MyNumber(%d)" % self.data
def __add__(self, other):
'''實現加法操作,生成一個新的物件並返回給呼叫者'''
print("__add__方法被呼叫")
return MyNumber(self.data + other.data)
def __sub__(self, rhs):
return MyNumber(self.data - rhs.data)
n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 + n2 # 等同於n1.__add__(n2)
# n3 = n1.__add__(n2)
print(n1, "+", n2, '=', n3) # MyNumber(300) ???
n4 = n1 - n2
print('n4 =', n4)
二元運算子的過載方法格式:
def __xxx__(self,other):
運算規則的語句...
反向算術運算子的過載
- 當運算子的左側為內建型別時,右側為自定義型別進行算術運算時,會出現TypeError錯誤,
- 因無法修改內建型別的程式碼來實現運算子過載,此時需要使用反向運算子過載來完成過載
反向算術運算過載
方法名 運算子和表示式 說明
radd(self,rhs) rhs + self 加法
rsub(self,rhs) rhs - self 減法
rmul(self,rhs) rhs * self 乘法
rtruediv(self,rhs) rhs / self 除法
rfloordiv(self,rhs) rhs // self 地板法
rmod(self,rhs) rhs % self 求餘(取模)
rpow(self,rhs) rhs ** self 冪運算
示例
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __mul__(self, rhs):
print("__mul__")
return MyList(self.data * rhs)
def __rmul__(self, lhs):
print("__rmul__被呼叫")
return MyList(self.data * lhs)
L1 = MyList([1, 2, 3])
L6 = 2 * L1 # 等同於2.__add__(L1) 或 L1.__rmul__(2)
print(L6)
複合賦值算術運算子過載
- 以複合賦值算術運算子為例x += y 為例,此運算子會優先呼叫x.iadd(y) 方法,
如果沒有__iadd__方法時會將複合賦值運算子拆為x = x + y,然後呼叫x = x.add(y) 方法
其它複合賦值算術運算子也具有相同的規則
複合算術運算過載
方法名 運算子和表示式 說明
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 冪運算
比較運算子的過載
方法名 運算子和表示式 說明
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
示例
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __gt__(self,rhs):
'''只比較第一個元素'''
print("__gt__被呼叫")
return self.data > rhs.data
def __eq__(self, rhs):
print('__eq__被呼叫')
return self.data == rhs.data
L1 = MyList([1, 2, 3])
L2 = MyList([1, 2, 3])
print(L1, '>', L2, '=', L1 > L2)
print(L1, '<', L2, '=', L1 < L2)
print(L1, '==', L2, 'is', L1 == L2)
print(L1, '!=', L2, 'is', L1 != L2)
位運算子的過載
方法名 運算子和表示式 說明
invert(self,rhs) ~self 取反(一元運算子)
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, rhs) lhs & self 位與
ror(self, rhs) lhs | self 位或
rxor(self, rhs) lhs ^ self 位異或
rlshift(self, rhs) lhs << self 左移
rrshift(self, rhs) 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 取反
語法格式:
def __xxx__(self):
...示例:
示例
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __neg__(self):
'''規則是正變負,負變正'''
# L = [-x for x in self.data]
L = (-x for x in self.data)
return MyList(L)
L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1 # 等同於L1.__neg__()
print(L2)
in / not in 運算子
contains(self, e) e in self 成員運算
索引和切片運算子的過載
[]
過載方法 運算子和表示式 說明
__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self,i,val) self.[i]=val 索引/切片賦值
__delitem__(self, i) del self[i] del語句索引/切片
作用:
讓自定義的型別的物件能夠支援索引和切片操作
示例
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __getitem__(self, i):
print("i =", i)
return self.data[i]
def __setitem__(self, i, val):
self.data[i] = val
L1 = MyList([1, -2, 3, -4, 5])
x = L1[0] # L1.__getitem__(0)
print(x)
L1[1] = 2 # L1.__setitem__(1, 2)
print(L1)
slice 建構函式
- 作用:
- 用於建立一個slice切片物件, 此物件儲存一個切片起始值,終止值, 步長值資訊
- 格式:
- slice(start=None, stop=None, step=None) 建立 一個slice 切片物件
- slice 物件屬性
- s.start 切片的起始值
- s.stop 切片的終止值
- s.step 要片的步長
特性屬性 @property
-
實現其它語言所擁有的 getter 和 setter功能
- 作用:
- 用來模擬一個屬性
- 通過@property裝飾器可以對模擬的屬性賦值和取值加以控制
- 作用:
示例
class Student:
def __init__(self, score):
self.__score = score
def get_score(self):
'''實現getter'''
return self.__score
def set_score(self, s):
'''實現setter'''
print("正在呼叫setter")
if 0 <= s <= 100:
self.__score = s
else:
raise ValueError
score = property(get_score, set_score)
s = Student(59)
print(s.score) # print(s.get_score())
s.score = 97 # s.set_score(97)
print(s.score) # ...
練習:
實現有序集合類 OrderSet 能實現兩個集合的
交集 & 全集 | 補集 - 對稱補集 ^ == / !=
in / not in 等集合操作
要求內部用list 儲存
class OrderSet:
…
s1 = OrderSet([1, 2, 3, 4])
s2 = OrderSet([3, 4, 5])
print(s1 & s2) # OrderSet([3, 4])
print(s1 | s2) # OrderSet([1, 2, 3, 4, 5])
print(s1 ^ s2) # OrderSet([1, 2, 5])
if OrderSet([1,2,3]) != OrderSet([1, 2, 3, 4]):
print(“不相等”)
if s2 == OrderSet([3,4,5]):
print(‘s2 等於 OrderSet([3,4,5])’)
if 2 in s1:
print(‘2 在s1內’)