自定義魔法方法(下)
阿新 • • 發佈:2021-01-07
一、str
在print輸出的時候會自動呼叫__str__
我們在自定義的時候必須要有返回值,且必須為字串
列印時觸發
class Foo: def __init__(self, name, age): """物件例項化的時候自動觸發""" self.name = name self.age = age def __str__(self): print('列印的時候自動觸發,但是其實不需要print即可列印') return f'{self.name}:{self.age}' # 如果不返回字串型別,則會報錯 obj = Foo('nick', 18) print(obj) # obj.__str__() # 列印的時候就是在列印返回值 ====>列印的時候自動觸發,但是其實不需要print即可列印 ====>nick:18 obj2 = Foo('tank', 30) print(obj2) ====>列印的時候自動觸發,但是其實不需要print即可列印 ====>tank:30
二、repr
str函式或者print函式—>obj.str()
repr或者互動式直譯器—>obj.repr()
如果str沒有被定義,那麼就會使用repr來代替輸出
注意:這倆方法的返回值必須是字串,否則丟擲異常
class School: def __init__(self, name, addr, type): self.name = name self.addr = addr self.type = type def __repr__(self): return 'School(%s,%s)' % (self.name, self.addr) def __str__(self): return '(%s,%s)' % (self.name, self.addr) s1 = School('oldboy1', '北京', '私立') print('from repr: ', repr(s1)) =====>from repr: School(oldboy1,北京) print('from str: ', str(s1)) ====>from str: (oldboy1,北京) print(s1) ====>(oldboy1,北京) s1 # jupyter屬於互動式 ====>School(oldboy1,北京)
三、實現迭代器(next__和__iter)
簡單示例
死迴圈
class Foo:
def __init__(self, x):
self.x = x
def __iter__(self):
return self
def __next__(self):
self.x += 1
return self.x
f = Foo(3)
for i in f:
print(i)
加上StopIteration異常
class Foo: def __init__(self, start, stop): self.num = start self.stop = stop def __iter__(self): return self def __next__(self): if self.num >= self.stop: raise StopIteration n = self.num self.num += 1 return n f = Foo(1, 5)
from collections import Iterable, Iterator
print(isinstance(f, Iterator))
====>True
for i in Foo(1, 5):
print(i)
====>1
====>2
====>3
====>4
模擬range
class Range:
def __init__(self, n, stop, step):
self.n = n
self.stop = stop
self.step = step
def __next__(self):
if self.n >= self.stop:
raise StopIteration
x = self.n
self.n += self.step
return x
def __iter__(self):
return self
for i in Range(1, 7, 3):
print(i)
====>1
====>4
斐波那契數列
class Fib:
def __init__(self):
self._a = 0
self._b = 1
def __iter__(self):
return self
def __next__(self):
self._a, self._b = self._b, self._a + self._b
return self._a
f1 = Fib()
for i in f1:
if i > 100:
break
print('%s ' % i, end='')
====>1 1 2 3 5 8 13 21 34 55 89
四、module
module 表示當前操作的物件在那個模組
print(obj.__module__) # 輸出 lib.aa,即:輸出模組
五、class
class表示當前操作的物件的類是什麼
print(obj.__class__) # 輸出 lib.aa.C,即:輸出類
六、實現檔案上下文管理(enter__和__exit)
我們知道在操作檔案物件的時候可以這麼寫
with open('a.txt') as f:
'程式碼塊'
上述叫做上下文管理協議,即with語句,為了讓一個物件相容with語句,必須在這個物件的類中宣告enter和exit方法
上下文管理協議
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中程式碼塊執行完畢時執行我啊')
with Open('a.txt') as f:
print('=====>執行程式碼塊')
# print(f,f.name)
出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數
=====>執行程式碼塊
with中程式碼塊執行完畢時執行我啊
exit()中的三個引數分別代表異常型別,異常值和追溯資訊,with語句中程式碼塊出現異常,則with後的程式碼都無法執行
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中程式碼塊執行完畢時執行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
try:
with Open('a.txt') as f:
print('=====>執行程式碼塊')
raise AttributeError('***著火啦,救火啊***')
except Exception as e:
print(e)
出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數
=====>執行程式碼塊
with中程式碼塊執行完畢時執行我啊
<class 'AttributeError'>
***著火啦,救火啊***
<traceback object at 0x1065f1f88>
***著火啦,救火啊***
如果__exit()返回值為True,那麼異常會被清空,就好像啥都沒發生一樣,with後的語句正常執行
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中程式碼塊執行完畢時執行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Open('a.txt') as f:
print('=====>執行程式碼塊')
raise AttributeError('***著火啦,救火啊***')
print('0' * 100) #------------------------------->會執行
出現with語句,物件的__enter__被觸發,有返回值則賦值給as宣告的變數
=====>執行程式碼塊
with中程式碼塊執行完畢時執行我啊
<class 'AttributeError'>
***著火啦,救火啊***
<traceback object at 0x1062ab048>
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
模擬open
class Open:
def __init__(self, filepath, mode='r', encoding='utf-8'):
self.filepath = filepath
self.mode = mode
self.encoding = encoding
def __enter__(self):
# print('enter')
self.f = open(self.filepath, mode=self.mode, encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
# print('exit')
self.f.close()
return True
def __getattr__(self, item):
return getattr(self.f, item)
with Open('a.txt', 'w') as f:
print(f)
f.write('aaaaaa')
f.wasdf #丟擲異常,交給__exit__處理
<_io.TextIOWrapper name='a.txt' mode='w' encoding='utf-8'>
優點:
1、使用with語句的目的就是把程式碼塊放入with中執行,with結束後,自動完成清理工作,無須手動干預
2、在需要管理一些資源比如檔案,網路連線和鎖的程式設計環境中,可以在exit中定製自動釋放資源的機制,你無須再去關係這個問題,這將大有用處