Python面向?qū)ο竽Хǚ椒ê蛦卫K代碼實(shí)例
魔法方法
凡是在類內(nèi)部定義,以“__開頭__結(jié)尾”的方法都稱之為魔法方法,又稱“類的內(nèi)置方法”, 這些方法會(huì)在某些條件成立時(shí)觸發(fā)。
經(jīng)常用到的雙下方法
- __init__: 在調(diào)用類時(shí)觸發(fā)。
- __delarttr__:
- __getattr__: 會(huì)在對(duì)象.屬性時(shí),“屬性沒(méi)有”的情況下才會(huì)觸發(fā)。對(duì)象.__dict__[屬性]不會(huì)觸發(fā)__getattr__,會(huì)報(bào)keyerror;
- __getattribute__:會(huì)在對(duì)象.屬性時(shí)觸發(fā),不管有沒(méi)有該屬性都會(huì)觸發(fā);
- __setattr__: 會(huì)在 “對(duì)象.屬性 = 屬性值” 時(shí)觸發(fā)。即:設(shè)置(添加/修改)屬性會(huì)觸發(fā)它的執(zhí)行;
- __del__: 當(dāng)對(duì)象在內(nèi)存中被釋放時(shí),自動(dòng)觸發(fā)執(zhí)行,該方法會(huì)在最后執(zhí)行。
class Uderline_func: x = 100 def __init__(self, y): print('類加括號(hào)調(diào)用的時(shí)候觸發(fā)我!') self.y = y # 當(dāng)與__setattr__方法同時(shí)存在時(shí),self.y = y并不會(huì)被加載到對(duì)象的名稱空間 # self['y'] = y # TypeError: 'Uderline_func' object does not support item assignment def general_func(self): print('隨便定義的一個(gè)函數(shù)!') # def __getattr__(self, item): # print('只有對(duì)象獲取一個(gè)沒(méi)有的屬性值得時(shí)候觸發(fā)我!') def __getattribute__(self, item): print('類或?qū)ο鬅o(wú)論獲取的屬性有沒(méi)有都會(huì)觸發(fā)我!且出現(xiàn)我,對(duì)象點(diǎn)一個(gè)沒(méi)有的屬性會(huì)覆蓋掉__getattr__,還會(huì)導(dǎo)致__setattr__函數(shù)報(bào)錯(cuò)') def __setattr__(self, key, value): print('設(shè)置屬性的時(shí)候觸發(fā)我!') # self.a = '在對(duì)象名稱空間增加一個(gè)值!' # 會(huì)一直觸發(fā)__setattr__,出現(xiàn)遞歸調(diào)用 self.__dict__['a'] = '在對(duì)象名稱空間增加一個(gè)值!' def __delattr__(self, item): print('刪除值得時(shí)候觸發(fā)我!') def __del__(self): print('程序運(yùn)行完,被Python解釋器回收時(shí),觸發(fā)我!') # print(Uderline_func.__dict__) # 類在定義階段就已經(jīng)創(chuàng)建好了類名稱空間,將其內(nèi)部變量名和函數(shù)名塞進(jìn)去 u = Uderline_func(100) # 觸發(fā)__init__ # print(u.__dict__) # {'y': 100} # Uderline_func.z # 只會(huì)觸發(fā)__getattribute__ u.z # 獲取沒(méi)有的屬性觸發(fā)__getattr__ # u.name = 'zhang' # 觸發(fā)__setattr__ # del u.x # 對(duì)象不能刪除掉類中的屬性,但只要執(zhí)行刪除操作,都會(huì)觸發(fā)__delattr__的執(zhí)行
- __str__: 會(huì)在打印對(duì)象時(shí)觸發(fā)。
- __call__: 會(huì)在對(duì)象被調(diào)用時(shí)觸發(fā)。
- __new__: 會(huì)在__init__執(zhí)行前觸發(fā)。
class Uderline_func(): x = 100 # def __new__(cls, *args, **kwargs): # # print('在__init__執(zhí)行之前觸發(fā)我,造一個(gè)空對(duì)象!') def __init__(self): print('類加括號(hào)調(diào)用的時(shí)候觸發(fā)我!') def __call__(self, *args, **kwargs): print('對(duì)象加括號(hào)調(diào)用的時(shí)候觸發(fā)我!') def __str__(self): print('對(duì)象被打印的時(shí)候觸發(fā)我!') return '必須要寫return返回一個(gè)字符串!不然報(bào)錯(cuò)"TypeError: __str__ returned non-string (type NoneType)"' u = Uderline_func() u() print(u)
__setitem__,__getitem,__delitem__
class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): self.__dict__[key]=value # self.age = value # 也可以給對(duì)象添加屬性 def __delitem__(self, key): print('del obj[key]時(shí),我執(zhí)行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key時(shí),我執(zhí)行') self.__dict__.pop(item) f1=Foo('sb') f1['age']=18 # print(f1.__dict__) f1['age1']=19 # del f1.age1 # del f1['age'] f1['name']='alex' f1.xxx = 111 print(f1.__dict__) # {'name': 'alex', 'age': 18, 'age1': 19, 'xxx': 111}
1.__slots__是什么:是一個(gè)類變量,變量值可以是列表,元祖,或者可迭代對(duì)象,也可以是一個(gè)字符串(意味著所有實(shí)例只有一個(gè)數(shù)據(jù)屬性)
2.引子:使用點(diǎn)來(lái)訪問(wèn)屬性本質(zhì)就是在訪問(wèn)類或者對(duì)象的__dict__屬性字典(類的字典是共享的,而每個(gè)實(shí)例的是獨(dú)立的)
3.為何使用__slots__:字典會(huì)占用大量?jī)?nèi)存,如果你有一個(gè)屬性很少的類,但是有很多實(shí)例,為了節(jié)省內(nèi)存可以使用__slots__取代
實(shí)例的__dict__
當(dāng)你定義__slots__后,__slots__就會(huì)為實(shí)例使用一種更加緊湊的內(nèi)部表示。實(shí)例通過(guò)一個(gè)很小的固定大小的數(shù)組來(lái)構(gòu)建,而不是為每個(gè)實(shí)例定義一個(gè)字典,這跟元組或列表很類似。在__slots__中列出的屬性名在內(nèi)部被映射到這個(gè)數(shù)組的指定小標(biāo)上。使用__slots__一個(gè)不好的地方就是我們不能再給實(shí)例添加新的屬性了,只能使用在__slots__中定義的那些屬性名。
4.注意事項(xiàng):__slots__的很多特性都依賴于普通的基于字典的實(shí)現(xiàn)。另外,定義了__slots__后的類不再 支持一些普通類特性了,比如多繼承。大多數(shù)情況下,你應(yīng)該只在那些經(jīng)常被使用到 的用作數(shù)據(jù)結(jié)構(gòu)的類上定義__slots__比如在程序中需要?jiǎng)?chuàng)建某個(gè)類的幾百萬(wàn)個(gè)實(shí)例對(duì)象 。
關(guān)于__slots__的一個(gè)常見誤區(qū)是它可以作為一個(gè)封裝工具來(lái)防止用戶給實(shí)例增加新的屬性。盡管使用__slots__可以達(dá)到這樣的目的,但是這個(gè)并不是它的初衷。 更多的是用來(lái)作為一個(gè)內(nèi)存優(yōu)化工具。
class Foo: __slots__ = 'x' f1 = Foo() f1.x = 1 f1.y = 2 # 報(bào)錯(cuò) print(f1.__slots__) # f1不再有__dict__屬性 print(f1.x) #依然能訪問(wèn) class Bar: __slots__ = ['x', 'y'] n = Bar() n.x, n.y = 1, 2 n.z = 3 # 報(bào)錯(cuò)
__doc__:查看類中注釋
class Foo: '我是描述信息' pass print(Foo.__doc__) class Foo: '我是描述信息' pass class Bar(Foo): pass print(Bar.__doc__) #該屬性無(wú)法繼承給子類
__module__和__class__
__module__:表示當(dāng)前操作的對(duì)象在那個(gè)模塊
__class__:表示當(dāng)前操作的對(duì)象的類是什么
class C: def __init__(self): self.name = ‘SB' from lib.aa import C obj = C() print obj.__module__ # 輸出 lib.aa,即:輸出模塊 print obj.__class__ # 輸出 lib.aa.C,即:輸出類
__enter__和__exit__
我們知道在操作文件對(duì)象的時(shí)候可以這么寫
with open('a.txt') as f:
'代碼塊'
上述叫做上下文管理協(xié)議,即with語(yǔ)句,為了讓一個(gè)對(duì)象兼容with語(yǔ)句,必須在這個(gè)對(duì)象的類中聲明__enter__和__exit__方法
class Open: def __init__(self,name): self.name=name def __enter__(self): print('出現(xiàn)with語(yǔ)句,對(duì)象的__enter__被觸發(fā),有返回值則賦值給as聲明的變量') # return self def __exit__(self, exc_type, exc_val, exc_tb): print('with中代碼塊執(zhí)行完畢時(shí)執(zhí)行我啊') with Open('a.txt') as f: print('=====>執(zhí)行代碼塊') # print(f,f.name) ''' 出現(xiàn)with語(yǔ)句,對(duì)象的__enter__被觸發(fā),有返回值則賦值給as聲明的變量 =====>執(zhí)行代碼塊 with中代碼塊執(zhí)行完畢時(shí)執(zhí)行我啊 '''
exit()中的三個(gè)參數(shù)分別代表異常類型,異常值和追溯信息,with語(yǔ)句中代碼塊出現(xiàn)異常,則with后的代碼都無(wú)法執(zhí)行
class Open: def __init__(self,name): self.name=name def __enter__(self): print('出現(xiàn)with語(yǔ)句,對(duì)象的__enter__被觸發(fā),有返回值則賦值給as聲明的變量') def __exit__(self, exc_type, exc_val, exc_tb): print('with中代碼塊執(zhí)行完畢時(shí)執(zhí)行我啊') print(exc_type) print(exc_val) print(exc_tb) with Open('a.txt') as f: print('=====>執(zhí)行代碼塊') raise AttributeError('***著火啦,救火啊***') print('0'*100) #------------------------------->不會(huì)執(zhí)行 ''' 出現(xiàn)with語(yǔ)句,對(duì)象的__enter__被觸發(fā),有返回值則賦值給as聲明的變量 =====>執(zhí)行代碼塊 with中代碼塊執(zhí)行完畢時(shí)執(zhí)行我啊 <class 'AttributeError'> ***著火啦,救火啊*** <traceback object at 0x000000000A001E88> Traceback (most recent call last): File "G:/Python代碼日常/第一階段/1階段/面向?qū)ο?test.py", line 52, in <module> raise AttributeError('***著火啦,救火啊***') AttributeError: ***著火啦,救火啊*** '''
如果__exit()返回值為True,那么異常會(huì)被清空,就好像啥都沒(méi)發(fā)生一樣,with后的語(yǔ)句正常執(zhí)行
class Open: def __init__(self,name): self.name=name def __enter__(self): print('出現(xiàn)with語(yǔ)句,對(duì)象的__enter__被觸發(fā),有返回值則賦值給as聲明的變量') def __exit__(self, exc_type, exc_val, exc_tb): print('with中代碼塊執(zhí)行完畢時(shí)執(zhí)行我啊') print(exc_type) print(exc_val) print(exc_tb) return True with Open('a.txt') as f: print('=====>執(zhí)行代碼塊') raise AttributeError('***著火啦,救火啊***') print('0'*100) #------------------------------->會(huì)執(zhí)行
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__處理
用途或者說(shuō)好處:
1.使用with語(yǔ)句的目的就是把代碼塊放入with中執(zhí)行,with結(jié)束后,自動(dòng)完成清理工作,無(wú)須手動(dòng)干預(yù)
2.在需要管理一些資源比如文件,網(wǎng)絡(luò)連接和鎖的編程環(huán)境中,可以在__exit__中定制自動(dòng)釋放資源的機(jī)制,你無(wú)須再去關(guān)系這個(gè)問(wèn)題,這將大有用處
單例模式
單例模式:多次實(shí)例化的結(jié)果指向同一個(gè)實(shí)例
方式1
# @classmethod(用類綁定方法) import settings class MySQL: __instance=None def __init__(self, ip, port): self.ip = ip self.port = port @classmethod def from_conf(cls): if cls.__instance is None: cls.__instance=cls(settings.IP, settings.PORT) return cls.__instance obj1=MySQL.from_conf() obj2=MySQL.from_conf() obj3=MySQL.from_conf() # obj4=MySQL('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) # print(obj4)
方式2
# 用類裝飾器 import settings def singleton(cls): _instance=cls(settings.IP,settings.PORT) def wrapper(*args,**kwargs): if len(args) !=0 or len(kwargs) !=0: obj=cls(*args,**kwargs) return obj return _instance return wrapper @singleton #MySQL=singleton(MySQL) #MySQL=wrapper class MySQL: def __init__(self, ip, port): self.ip = ip self.port = port # obj=MySQL('1.1.1.1',3306) #obj=wrapper('1.1.1.1',3306) # print(obj.__dict__) obj1=MySQL() #wrapper() obj2=MySQL() #wrapper() obj3=MySQL() #wrapper() obj4=MySQL('1.1.1.3',3302) #wrapper('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) print(obj4)
方式3
# 調(diào)用元類 import settings class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=MySQL這個(gè)類 self.__instance=self(settings.IP,settings.PORT) def __call__(self, *args, **kwargs): # self=MySQL這個(gè)類 if len(args) != 0 or len(kwargs) != 0: obj=self.__new__(self) self.__init__(obj,*args, **kwargs) return obj else: return self.__instance class MySQL(metaclass=Mymeta): #MySQL=Mymeta(...) def __init__(self, ip, port): self.ip = ip self.port = port obj1=MySQL() obj2=MySQL() obj3=MySQL() obj4=MySQL('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) print(obj4)
方式4
# 利用模塊多次導(dǎo)入只產(chǎn)生一次名稱空間,多次導(dǎo)入只沿用第一次導(dǎo)入成果。 def f1(): from singleton import instance print(instance) def f2(): from singleton import instance,My SQL print(instance) obj=MySQL('1.1.1.3',3302) print(obj) f1() f2()
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
TensorFlow進(jìn)階學(xué)習(xí)定制模型和訓(xùn)練算法
本文將為你提供關(guān)于 TensorFlow 的中級(jí)知識(shí),你將學(xué)習(xí)如何通過(guò)子類化構(gòu)建自定義的神經(jīng)網(wǎng)絡(luò)層,以及如何自定義訓(xùn)練算法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07Python發(fā)送手機(jī)動(dòng)態(tài)驗(yàn)證碼代碼實(shí)例
這篇文章主要介紹了Python發(fā)送手機(jī)動(dòng)態(tài)驗(yàn)證碼代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02python中join與os.path.join()函數(shù)實(shí)例詳解
os.path.join()函數(shù)用于路徑拼接文件路徑,下面這篇文章主要給大家介紹了關(guān)于python中join與os.path.join()函數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03Python使用captcha庫(kù)制作帶參數(shù)輸入驗(yàn)證碼案例
這篇文章主要介紹了Python使用captcha庫(kù)制作驗(yàn)證碼,帶參數(shù)輸入,本文通過(guò)實(shí)例案例解析給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05softmax及python實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了softmax及python實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09python類的方法屬性與方法屬性的動(dòng)態(tài)綁定代碼詳解
這篇文章主要介紹了python類的方法屬性與方法屬性的動(dòng)態(tài)綁定代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12python調(diào)用java模塊SmartXLS和jpype修改excel文件的方法
這篇文章主要介紹了python調(diào)用java模塊SmartXLS和jpype修改excel文件的方法,涉及Python調(diào)用java模塊的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04使用keras時(shí)input_shape的維度表示問(wèn)題說(shuō)明
這篇文章主要介紹了使用keras時(shí)input_shape的維度表示問(wèn)題說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06