PythonOOP面向對象編程3
阿新 • • 發佈:2019-03-22
協議 一個 item 運算 read getitem 語句 金毛 刪除
override 函數重寫
- 重寫是在自定義的類內添加相應的方法,讓自定義的類生成的對象(實例)像內建對象一樣進行內建的函數操作
對象轉字符串函數重寫
- repr(obj) 返回一個能代表此對象的表達式字符串(帶引號的可以執行),通常:
- eval(repr(obj)) == obj
str(obj) 通常給定的對象返回一個字符串(這個字符串通常是給人看的)
- 對象轉字符串函數重寫方法:
- repr() 函數的重寫方法:
def __repr__(self): return 能夠表達self內容的字符串
- srt() 函數的重寫方法:
def __str__(self: return 人能看懂的字符串
- repr() 函數的重寫方法:
- 說明:
- str(obj) 函數優先調用obj.__str__()方法返回字符串
- 如果obj沒有__str__()方法,則調用obj.__str__()方法返回的字符串
- 如果obj沒有__repr__()方法, 則調用obj.__repr__()實例方法顯示
格式的字符串
# 此示例示意一個自定義的數字類型重寫repr和str方法的用法 class MyNumber: def __init__(self, value): self.data = value def __str__(self): print("str被調用") return "數字:%d" % self.data def __repr__(self): print("repr被調用") return "MyNumber(%d)" % self.data # def __len__(self): # 重寫了len # return 100 # n1 = MyNumber() # x = len(n1) # print(x) n1 = MyNumber(100) print(str(n1)) print(repr(n1)) print(n1)
str被調用
數字:100
repr被調用
MyNumber(100)
str被調用
數字:100
數值轉換函數的重寫
- def __complex__(self) complex(obj) 函數調用
- def __int__(self) int(obj) 函數調用
- def __float__(self) float(obj) 函數調用
- def __bool__(self) bool(obj) 函數調用
# 此示例示意自定義的類MyNumber能夠轉成數值類型 class MyNumber: def __init__(self, v): self.data = v def __repr(self): return "MyNumber(%d)" % self.data def __int__(self): '''此方法用於int(obj) 函數重載,必須返回整數 此方法通常用於制定自定義對象如何轉為整數的規則 ''' return 10000 n1 = MyNumber(100) print(type(n1)) n = int(n1) print(n, type(n))
<class '__main__.MyNumber'>
10000 <class 'int'>
內建函數重寫
- __abs__ abs(obj)
- __len__ len(obj)
- __reversed__ reversed(obj)
- __round__ round(obj)
# 自定義一個MyList,與系統內建的類一樣,用來保存有先後順序關系的數據
class MyList:
'''自定義列表類'''
def __init__(self, iterator=[]):
self.data = [x for x in iterator]
def __repr__(self):
return "MyList(%r)" % self.data
def __abs__(self):
return MyList([abs(x) for x in self.data])
def __len__(self):
return len(self.data)
myl = MyList([1, -2, 3, -4])
print(myl)
print("絕對值列表是:", abs(myl))
myl2 = MyList(range(10))
print(myl2)
print("ml2的長度是:", len(myl2))
MyList([1, -2, 3, -4])
MyList([1, 2, 3, 4])
MyList([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
10
布爾測試函數的重寫
格式:
def __bool__(self):
- 作用:
- 用於bool(obj) 函數取值
- 用於if語句真值表達式中
- 用於while語句真值表達式中
- 說明:
- 優先調用__bool__方法取值
- 如果不存在__bool__方法,則用__len__()方法取值,如果不為零返回True,否則返回Fales
- 如果再沒有__len__方法,則直接返回True
class MyList:
'''自定義列表類'''
def __init__(self, iterator=[]):
self.data = [x for x in iterator]
def __repr__(self):
return "MyList(%r)" % self.data
def __abs__(self):
return MyList([abs(x) for x in self.data])
def __len__(self):
return len(self.data)
myl = MyList([1, -2, 3, -4])
print(bool(myl)) # True 調用了len,若len也沒有,返回True
True
叠代器(高級)
- 什麽是叠代器
- 可以通過next(it) 函數取值的對象就是叠代器
- 叠代器協議:
- 叠代器協議是指對象能夠使用next函數獲取下一項數據,在沒有下一項數據時出發一個StopIterator來種植叠代的約定
- 實現方法:
- 類內需要有__next__(self) 方法來實現叠代器協議
- 語法:
class MyIterator: def __next__(self): 叠代器協議的實現 return 數據
- 什麽是可叠代對象
- 是指能用iter(obj) 函數返回叠代器的對象(實例)可叠代對象內部一定要定義__iter__(self)方法來返回叠代器
# 此示例示意可叠代對象和叠代器的定義以及使用方法:
class MyList:
def __init__(self, iterator):
'''自定義列表的初始化方法,此方法創建一個data實例變量
來綁定一個用來存儲數據的列表'''
self.data = list(iterator)
def __repr__(self):
'''此方法為了打印此列表數據'''
return 'MyList(%r)' % self.data
def __iter__(self):
'''有此方法就是可叠代對象,但是要求必須返回叠代器'''
print("__iter__方法被調用")
return MyListIterator(self.data)
class MyListIterator:
'''此類用來創建一個叠代器對象,用此叠代器對象可以訪問
MyList類型的數據'''
def __init__(self, iter_data):
self.cur = 0 # 設置叠代器的初始值為0,代表列表的索引
# it_data 綁定要叠代的列表
self.iter_data = iter_data
def __next__(self):
'''有此方法的對象才叫叠代器,
此方法一定要實現叠代器協議'''
# 如果self.cur已經超出了列表的索引範圍,就報叠代結束錯誤
if self.cur >= len(self.iter_data):
raise StopIteration
# 否則尚未叠代完成,需要返回數據
r = self.iter_data[self.cur] # 拿到要送回去的數
self.cur += 1 # 將當前值向後移動一個單位
return r
myl = MyList([2,3,5,7])
print(myl)
for x in myl:
print(x)
MyList([2, 3, 5, 7])
__iter__方法被調用
2
3
5
7
異常(高級)
- 回顧異常相關的語句:
- try-except 用來捕獲異常通知
- try-finally 用來做一定要做的事情
- raise 用來發生異常通知
- assert 用來根據條件發出AssertionError類型的異常通知
with 語句
- 語法:
with 表達式1 [as 變量1], 表達式2 [as 變量2]: 語句塊
- 作用:
- 使用於對資源進行訪問的場合,確保使用過程中不管是否發生異常,都會執行必須"清理"操作,並釋放資源
- 如:文件使用後自動關閉,線程中鎖的自動獲取和釋放等
- 使用於對資源進行訪問的場合,確保使用過程中不管是否發生異常,都會執行必須"清理"操作,並釋放資源
- 說明:
- 能夠用於with語句進行管理的對象必須是環境管理器
# 此示例用try-except和try-finally組合來對文件進行操作
def read_from_file(filename='info.txt'):
try: # 確保文件不崩潰
f = open(filename)
try: # 這個try用來確保能夠close
print("正在讀取文件")
n = int(f.read())
finally:
f.close()
except OSError:
print("文件打開失敗")
read_from_file()
文件打開失敗
#
def read_from_file(filename='info.txt'):
try: # 確保文件不崩潰
with open(filename) as f: # with 會自動調用close
print("正在讀取文件")
n = int(f.read())
print("n=", n)
print("文件已關閉")
except OSError:
print("文件打開失敗")
read_from_file()
正在讀取文件
n= 123
文件已關閉
環境管理器
- 類內有__enter__ 和 __exit__實例方法的類被成文環境管理器
- 能夠用with語句管理的對象必須是環境管理器
- __enter__方法將在進入with語句時被調用,並返回由as變量管理的對象
- __exit__將在離開with語句時被調用,並且可以用參數來判斷在離開with語句時是否有異常發生,並作出相應處理
class A:
def __enter__(self):
print("已進入with語句")
return self # 返回的對象由as綁定
def __exit__(self, exc_type, exc_val, exc_tb):
'''此方法會在退出with語句時自動調用
exc_type 在沒有異常時為None,出現異常時為異常類型
exc_val 在沒有異常時為None,出現異常時綁定錯誤對象
exc_tb 在沒有異常時為None,在出現異常時綁定traceback'''
if exc_type is None:
print("已離開with語句,離開時狀態正常")
else:
print("已離開with語句,離開時狀態異常")
print("異常類型是:", exc_type)
print("錯誤對象時:", exc_val)
print("traceback是:", exc_tb)
a = A()
with A() as a:
print("以下是with語句內的一條語句")
int(input())
已進入with語句
以下是with語句內的一條語句
a
已離開with語句,離開時狀態異常
異常類型是: <class 'ValueError'>
錯誤對象時: invalid literal for int() with base 10: 'a'
traceback是: <traceback object at 0x10bc99888>
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-31-5e7aa7e26050> in <module>
21 with A() as a:
22 print("以下是with語句內的一條語句")
---> 23 int(input())
ValueError: invalid literal for int() with base 10: 'a'
對象的屬性管理函數
- getattr(obj, name[, default])
- 從一個對象得到對象的屬性;getattr(x,‘y‘)等同於x.y;當屬性不存在時,如果給出default參數,則返回default;如果沒有給出default則產生一個ArributeError錯誤
- hasattr(obj, name)
- 用給定的name返回對象obj是否有該屬性,此種做法可以避免在getattr(obj, name)時引發錯誤
- setattr(obj, name, value)
- 給對象obj的名為name的屬性設置相應的值value,set(x, ‘y‘, v)等同於x.y = v
- delattr(obj, name)
- 刪除對象obj中的name屬性,delattr(x, ‘y‘)等同於def x.y
class Dog:
pass
dog1 = Dog()
print(getattr(dog1, 'color', '沒有顏色'))
dog1.color = 'Yellow'
print(getattr(dog1, 'color', '沒有顏色'))
dog2 = Dog()
setattr(dog2, 'kind', '金毛')
print(dog2.kind)
delattr(dog2, 'kind')
沒有顏色
Yellow
金毛
運算符重載
讓自定義的類生成的對象(實例)能夠運用運算符進行操作
- 作用:
- 讓自定義的類的實例像內建對象一樣運行運算符操作
- 讓程序簡介易讀
- 對自定義的對象,將運算符賦予新的運算規則
算術運算符的重載:
__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 冪
- 說明:
- 運算符重載不能改變運算的優先級
class MyNumber:
def __init__(self, v):
self.data = v
def __repr__(self):
return "MyNumber(%d)" % self.data
def __add__(self, other):
print("__add__被調用")
v = self.data + other.data
return MyNumber(v)
def __sub__(self, other):
print("__sub__被調用")
v = self.data - other.data
return MyNumber(v)
n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 + n2
n4 = n2 - n1
print(n3, n4)
class MyList:
def __init__(self, iterable):
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __add__(self, other):
return MyList(self.data + other.data)
def __mul__(self, num):
return MyList(self.data * num)
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L3 = L1 + L2
print(L3) # MyList([1, 2, 3, 4, 5, 6])
L4 = L2 + L1
print(L4) # MyList([4, 5, 6, 1, 2, 3])
L5 = L1 * 2
print(L5) # MyList([1, 2, 3, 1, 2, 3])
__add__被調用
__sub__被調用
MyNumber(300) MyNumber(100)
MyList([1, 2, 3, 4, 5, 6])
MyList([4, 5, 6, 1, 2, 3])
MyList([1, 2, 3, 1, 2, 3])
反向算術運算符重載:
__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 冪
class MyList:
def __init__(self, iterable):
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __add__(self, other):
return MyList(self.data + other.data)
def __mul__(self, num):
'mul被調用'
return MyList(self.data * num)
def __rmul__(self, num):
'rmul被調用'
return MyList(self.data * num)
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L4 = L1 * 2
L5 = 3 * L1
print(L4)
print(L5)
MyList([1, 2, 3, 1, 2, 3])
MyList([1, 2, 3, 1, 2, 3, 1, 2, 3])
復合賦值算術運算符重載
__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 冪
class MyList:
def __init__(self, iterable):
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __add__(self, other):
return MyList(self.data + other.data)
def __mul__(self, num):
return MyList(self.data * num)
def __iadd__(self, rhs):
print("__iadd__被調用!")
self.data.extend(rhs.data)
return self
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L1 += L2 # 當沒有__iadd__方法時,等同於調用L1 = L1 + L2
print(L1)
__iadd__被調用!
MyList([1, 2, 3, 4, 5, 6])
- 問題
L = [1,2,3]
def f1():
global L # 這裏必須加global L
L = L + [4, 5, 6]
f1()
print(L)
def f2():
# 這裏就不用加global L
L += [4, 5, 6] # 這裏相當於調用了L.__iadd__([4, 5, 6])
f2()
比較運算符的重載
__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
位運算符重載
__invert__(self) ~ 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 取反
# 一元運算符的重載方法:
class MyList:
def __init__(self, iterable):
print("__init__被調用")
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __neg__(self):
'''此方法用來制定-self返回的規則'''
L = [-x for x in self.data]
return MyList(L)
L1 = MyList([1, -2, 3, -4])
L2 = -L1
print(L2)
__init__被調用
__init__被調用
MyList([-1, 2, -3, 4])
in / not in 運算符的重載
- 重載方法:
class MyList:
def __init__(self, iterable):
print("__init__被調用")
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __contains__(self, e):
'''此方法用來實現 in / not in 運算符的重載'''
print("__contains__被調用")
for x in self.data:
if x == e:
return True
return False
L1 = MyList([1, -2, 3, -4])
if -2 in L1:
print("-2 在 L1 中")
else:
print("-2 不在 L1 中")
__init__被調用
__contains__被調用
-2 在 L1 中
索引和切片運算符重載
__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self, i, v) self[i] = v 索引/切片賦值
__delitem__(self, i) del self[i] del語句刪除索引等
- 作用:
- 讓自定義類型的對象能夠支持索引和切片操作
# 此示例示意[]運算符的重載
class MyList:
def __init__(self, iterable):
print("__init__被調用")
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __getitem__(self, i):
print("__getitem__被調用, i=", i)
return self.data[i]
def __setitem__(self, i, v):
print("__setitem__被調用, i=", i, 'v = ', v)
self.data[i] = v
L1 = MyList([1, -2, 3, -4])
v = L1[0]
print(v)
L1[1] = 2 # 等同於調用L1.__setitem__(1, 2)
print(L1)
__init__被調用
__getitem__被調用, i= 0
1
__setitem__被調用, i= 1 v = 2
MyList([1, 2, 3, -4])
slice 函數
- 作用:
- 用於創建一個slice切片對象,此對象存儲一個切片的起始值、中止值和步長信息
slice(start, stope=None, step=None) 創建一個切片對象
- 屬性:
- s.start 切片起始值,默認為None
- s.stop 切片中止值,默認為None
- s.step 切片步長,默認為None
class MyList:
def __init__(self, iterable):
print("__init__被調用")
self.data = list(iterable)
def __repr__(self):
return "MyList(%r)" % self.data
def __getitem__(self, i):
print("__getitem__被調用, i=", i)
if type(i) is int:
print("正在做索引操作")
elif type(i) is slice:
print("正在做切片操作")
print("切片的起始值為:", i.start)
print("切片的中止值為:", i.stop)
print("切片的步長值為:", i.step)
return self.data[i]
L1 = MyList([1, -2, 3, -4, 5, -6])
print(L1[::2]) # 相當於 L1[slice(None, None, 2)] L.__getitem__(slice(None, None, None))
__init__被調用
__getitem__被調用, i= slice(None, None, 2)
正在做切片操作
切片的起始值為: None
切片的中止值為: None
切片的步長值為: 2
[1, 3, 5]
PythonOOP面向對象編程3