面向對象之內置方法續集
接上一篇,內置方法續集:
六、__str__,__repr__ 和 __format__
1、作用:__str__,__repr__ 改變對象的字符串顯示
__format__ 自定制格式化字符串
2、示例:
#!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong format_dict={ ‘way1‘:‘{obj.name}-{obj.addr}-{obj.type}‘,#學校名-學校地址-學校類型 ‘way2‘:‘{obj.type}:{obj.name}:{obj.addr}View Code‘,#學校類型:學校名:學校地址 ‘way3‘:‘{obj.type}/{obj.addr}/{obj.name}‘,#學校類型/學校地址/學校名 } 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) def __format__(self, format_spec): if not format_spec or format_spec not in format_dict: format_spec = ‘way1‘ fmt =format_dict[format_spec] return fmt.format(obj=self) s1 = School(‘lufei‘,‘上海‘,‘培訓機構‘) print(‘from repr:‘,repr(s1)) # from repr: School(lufei,上海) print(‘from str:‘,str(s1)) # from str: (lufei,上海) print(s1) # (lufei,上海) print(format(s1,‘way2‘))# 培訓機構:lufei:上海 print(format(s1,‘way3‘)) # 培訓機構/上海/lufei print(format(s1,‘abcdef‘)) # 培訓機構/上海/lufei ‘‘‘ str函數或者print函數--->obj.__str__() repr或者交互式解釋器--->obj.__repr__() 如果__str__沒有被定義,那麽就會使用__repr__來代替輸出 ‘‘‘
註意:__str__和__repr__方法的返回值必須是字符串,否則拋出異常。
七、slots的用法
1、__slots__是什麽?
__slots__是一個類變量,變量值可以是列表,元祖,或者可叠代對象,也可以是一個字符串(意味著所有實例只有一個數據屬性)。
2、使用點來訪問屬性本質就是在訪問類或者對象的__dict__屬性字典(類的字典是共享的,而每個實例的是獨立的)。
3、使用__slots__方法的好處?
字典會占用大量內存,如果你有一個屬性很少的類,但是有很多實例,為了節省內存可以使用__slots__取代實例的__dict__
當你定義__slots__後,__slots__就會為實例使用一種更加緊湊的內部表示。實例通過一個很小的固定大小的數組來構建,而不是為每個實例定義一個
字典,這跟元組或列表很類似。在__slots__中列出的屬性名在內部被映射到這個數組的指定小標上。使用__slots__一個不好的地方就是我們不能再給
實例添加新的屬性了,只能使用在__slots__中定義的那些屬性名。
4、註意:__slots__的很多特性都依賴於普通的基於字典的實現。另外,定義了__slots__後的類不再 支持一些普通類特性了,比如多繼承。
大多數情況下,你應該只在那些經常被使用到 的用作數據結構的類上定義__slots__比如在程序中需要創建某個類的幾百萬個實例對象 。它更多的是
用來作為一個內存優化工具。
5、示例:
#!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong class Test: __slots__ = [‘name‘,‘age‘] f1 = Test() f1.name = ‘cc‘ f1.age = 21 print(f1.__slots__) # [‘name‘, ‘age‘] #print(f1.__dict__) 報錯,f1不再有__dict__ # f1.sex = ‘male‘ 報錯,f1不能再添加屬性 print(f1.__slots__) # [‘name‘, ‘age‘] f2 = Test() f2.name = ‘zm‘ f2.age = 19 print(f2.__slots__) # [‘name‘, ‘age‘] #f1與f2都沒有屬性字典__dict__了,統一歸__slots__管,節省內存 print(Test.__dict__)# {‘__module__‘: ‘__main__‘, ‘__slots__‘: [‘name‘, ‘age‘], ‘age‘: <member ‘age‘ of ‘Test‘ objects>, ‘name‘: <member ‘name‘ of ‘Test‘ objects>, ‘__doc__‘: None}View Code
八、__next__和__iter__實現叠代器協議
1、關於__next__和__iter__方法的幾點解釋
Python中關於叠代有兩個概念,第一個是Iterable,第二個是Iterator,協議規定Iterable的__iter__方法會返回一個Iterator,
Iterator的__next__方法(Python 2裏是next)會返回下一個叠代對象,如果叠代結束則拋出StopIteration異常。同時,Iterator自己也是一種Iterable,
所以也需要實現Iterable的接口,也就是__iter__,這樣在for當中兩者都可以使用。Iterator的__iter__只需要返回自己就行了。
這樣,下面的代碼就可以工作:
for i in my_list:
...
for i in iter(mylist):
...
for i in (v for v in mylist if v is not None):
...
2、示例1--叠代器:
class Range: def __init__(self,n,stop,step): # 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)View Code
3、示例2--斐波拉契數列:
# 斐波那契數列 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() print(f1.__next__()) print(next(f1)) print(next(f1)) for i in f1: if i > 100: break print(‘%s ‘ %i,end=‘‘)View Code
九、 __module__和__class__
1、__module__ 表示當前操作的對象在那個模塊、__class__ 表示當前操作的對象的類是什麽
2、示例:
#lib/a.py #!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong class C: def __init__(self): self.name = ‘cc‘ # index.py #from lib.a import C obj = C() print(obj.__module__) # 輸出 lib.a,即輸出模塊 print(obj.__class__) # 輸出lib.a.C ,輸出類View Code
十、__del__方法
1、含義:析構方法,當對象在內存中被釋放時,自動觸發執行。
2、為什麽用__del__方法?
如果產生的對象僅僅只是python程序級別的(用戶級),那麽無需定義__del__,如果產生的對象的同時還會向操作系統發起系統調用,
即一個對象有用戶級與內核級兩種資源,比如(打開一個文件,創建一個數據庫鏈接),則必須在清除對象的同時回收系統資源,這就用到了__del__。
3、應用場景
創建數據庫類,用該類實例化出數據庫鏈接對象,對象本身是存放於用戶空間內存中,而鏈接則是由操作系統管理的,
存放於內核空間內存中當程序結束時,python只會回收自己的內存空間,即用戶態內存,而操作系統的資源則沒有被回收,
這就需要我們定制__del__,在對象被刪除前向操作系統發起關閉數據庫鏈接的系統調用,回收資源
4、示例:
class Foo: def __del__(self): print(‘執行到我啦‘) f1=Foo() del f1 print(‘------->‘) ‘‘‘ #輸出結果 執行我到啦 -------> ‘‘‘View Code
十一、 __enter__和__exit__方法
with open(‘a.txt‘) as f: pass # 上述叫做上下文管理協議,即with語句,為了讓一個對象兼容with語句,必須在這個對象的類中聲明__enter__和__exit__方法 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): ‘‘‘ with語句中代碼塊出現異常,則with後的代碼都無法執行 如果__exit__()返回值為True,那麽異常會被清空,就好像啥都沒發生一樣,with後的語句正常執行 :param exc_type: 異常類型 :param exc_val: 異常值 :param exc_tb: 追溯信息 :return: ‘‘‘ # 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__處理View Code
使用with語句的好處:
使用with語句的目的就是把代碼塊放入with中執行,with結束後,自動完成清理工作,無須手動幹預
在需要管理一些資源比如文件,網絡連接和鎖的編程環境中,可以在__exit__中定制自動釋放資源的機制,
你無須再去關心這個問題。
十二、__call__方法
1、使用方法:對象後面加括號,觸發執行。
2、註意事項:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;
而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()。
3、示例:
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print(‘__call__‘)
obj = Foo() # 執行 __init__
obj() # 執行 __call__
View Code
十三、__doc__方法
1、作用:查看類的描述信息。
2、示例:
class Foo:
‘我是匆匆‘
pass
class Bar(Foo):
pass
print(Foo.__doc__) # 我是匆匆
print(Bar.__doc__) # None 該屬性無法繼承給子類
面向對象之內置方法續集