python基础知识整理 第七节:单例设计模式、异常、模块、包、制作模块、文件
1、單例設(shè)計模式
單例設(shè)計模式就是為對象在內(nèi)存中分配空間的時候,永遠(yuǎn)只會返回一個唯一的固定的內(nèi)存空間。這樣就能保證在內(nèi)存中這個類的對象只有唯一的一份,這個就叫做單例。(為對象分配空間使用的是內(nèi)置方法__new__方法)
創(chuàng)建對象時,new方法會被自動調(diào)用。如果自己重寫__new__方法,一定要進(jìn)行返回分配的內(nèi)存空間,如果不返回,pyhton的解釋器就得不到分配空間的對象引用,如果得不到對象的引用,python的解釋器就不會調(diào)用初始化方法,把對象的引用傳遞到初始化的方法內(nèi)部。
class MusicPlayer(object):#重寫new方法def __new__(cls,*args,**kwargs):#1.創(chuàng)建對象時,new方法會被自動調(diào)用print("創(chuàng)建對象,分配空間")#1使用print函數(shù)覆蓋了父類object方法的實現(xiàn)#2、為對象分配空間"""怎么樣為對象分配空間?可以直接調(diào)用父類的方法就好了,因為object基類中已經(jīng)默認(rèn)的new方法已經(jīng)可以實現(xiàn)為對象分配空間的動作了,所以我們可以直接調(diào)用一下父類的方法,要調(diào)用父類的方法,應(yīng)該找一個特殊的對象是super即super().__new__(cls),需要注意的是new方法是一個靜態(tài)的方法,所以我們在調(diào)用new方法的時候,必須要把第一個參數(shù)cls傳遞給這個方法。"""instance=super().__new__(cls)#3、返回對象的引用"""調(diào)用完父類的這個方法之后,怎么樣把方法的返回結(jié)果返回呢?1、可以直接在上邊加一個return2、還可以定義一個變量接收父類的返回結(jié)果(例如shiyong instance接收返回結(jié)果)"""return instance#2把對象的引用返回def __init__(self):#3返回之后,這樣python的解釋器就能夠自動調(diào)用初始化方法print("播放器初始化")
player=MusicPlayer()
print(player)#打印播放器的內(nèi)存地址(4初始化方法完成之后,在主程序中把創(chuàng)建好的播放器對象打印在控制臺)
結(jié)果:
PS:__new__方法中一定要返回父類方法調(diào)用__new__方法的結(jié)果就可以,而且new方法是一個靜態(tài)的方法,所以在調(diào)用父類方法的時候,必須要主動傳遞cls這個參數(shù)。
單例設(shè)計模式的思想:定義一個類屬性,類屬性的初始值為None,當(dāng)?shù)谝淮握{(diào)用創(chuàng)建對象方法時,我們就在類屬性中記錄住第一個對象的引用,當(dāng)再次調(diào)用創(chuàng)建對象方法時,再次調(diào)用創(chuàng)建方法的屬性時,是再次創(chuàng)建,表明第一個對象在內(nèi)存中已經(jīng)存在了,那么我們就直接把第一個對象的引用做一個返回,而不再調(diào)用父類的分配空間的這一個方法;不再調(diào)用父類的分配空間的這一個方法,所以就不會在類的內(nèi)存中為這個類的其他對象分配額外的內(nèi)存空間,而只是把之前記錄的第一個對象的引用做一個返回。再次調(diào)用時只是把第一個對象的引用做一個返回,這樣呢就能夠做到無論調(diào)用多少次創(chuàng)建對象的方法,我們得到的永遠(yuǎn)是第一個創(chuàng)建出來的對象的引用。--------------這個就是使用單例設(shè)計模式解決在內(nèi)存中只創(chuàng)建唯一一個實例的解決辦法。
使用單例設(shè)計模式來開發(fā)設(shè)計的類:
這就是怎么樣使用單例設(shè)計模式,在創(chuàng)建對象時,無論調(diào)用多少次創(chuàng)建對象的方法,得到的結(jié)果永遠(yuǎn)是第一個創(chuàng)建對象的實例。
class MusicPlayer(object):#1、記錄第一個被創(chuàng)建對象的引用instance=None#使用None作為初始值,因為類定義完成,第一個對象還沒有被創(chuàng)建,必須要主動調(diào)用一下創(chuàng)建對象的方法,第一個對象才能夠被創(chuàng)建,因此這個類屬性的初始值我們把它定義為None#2、改造new方法,因為new方法是負(fù)責(zé)分配內(nèi)存空間的def __new__(cls,*args,**kwargs):#1判斷類屬性是不是空對象,如果是空對象說明第一個對象還沒有被創(chuàng)建if cls.instance is None:#2如果對象沒有被創(chuàng)建,應(yīng)該調(diào)用父類的方法為第一個對象分配空間(只有為第一個對象分配空間之后我們才能夠使用類屬性進(jìn)行記錄)cls.instance=super().__new__(cls)#3如果類屬性中已經(jīng)有了值,就直接把類屬性中保存的第一個對象引用直接返回給python的解釋器就可以了return cls.instance#2把對象的引用返回#這樣無論在外界無論調(diào)用多少次創(chuàng)建對象的方法,得到的對象內(nèi)存地址永遠(yuǎn)都是相同的def __init__(self):#3返回之后,這樣python的解釋器就能夠自動調(diào)用初始化方法print("播放器初始化")
player1=MusicPlayer()
print(player1)player2=MusicPlayer()
print(player2)#地址一樣就表明player1和player2本質(zhì)上是相同的對象
結(jié)果:
現(xiàn)在實現(xiàn)了內(nèi)存中只有唯一的一個對象。但是初始化方法被調(diào)用了多次,即使用了幾次創(chuàng)建對象的方法初始化方法就被調(diào)用了幾次。
改進(jìn):讓初始化的動作只被調(diào)用一次。所謂初始化的動作就是我們寫在初始化方法內(nèi)部,對對象進(jìn)行初始化的代碼。
PS:初始化方法的調(diào)用我們不能限制,但是我們可以有特殊的方式來解決一下讓初始化的動作只被執(zhí)行一次。
class MusicPlayer(object):#1、記錄第一個被創(chuàng)建對象的引用instance=None#記錄是否執(zhí)行過初始化動作init_flag=False#表明最開始還未執(zhí)行過初始化的動作def __new__(cls,*args,**kwargs):if MusicPlayer.instance is None:MusicPlayer.instance=super().__new__(cls)return MusicPlayer.instance#2把對象的引用返回def __init__(self):#判斷是否執(zhí)行過初始化動作if MusicPlayer.init_flag:return#如果類屬性為真,表明已經(jīng)執(zhí)行過初始化操作,就直接返回#如果沒有執(zhí)行過初始化動作,在此執(zhí)行初始化動作print("播放器初始化")#修改初始化動作的標(biāo)記MusicPlayer.init_flag=True
player1=MusicPlayer()
print(player1)player2=MusicPlayer()
print(player2)#地址一樣就表明player1和player2本質(zhì)上是相同的對象
結(jié)果見上圖。
2、異常
程序在運行過程中遇到錯誤就會拋出異常。針對于異常我們要捕獲異常。
??
3、模塊
在python中每一個獨立的源文件(以py結(jié)尾)就是模塊。
導(dǎo)入模塊之后通過模塊名.使用模塊中提供的工具--------全局變量、函數(shù)、類。
寫完一個.py模塊后,我們需要使用一些測試代碼,判斷這個模塊是否可以正常運行,但是這些測試代碼在.py作為模塊導(dǎo)入之后,是不需要被執(zhí)行的。所以我們通過__name__這個屬性來判斷。
如果我們直接執(zhí)行當(dāng)前正在開發(fā)的模塊(就是直接執(zhí)行py這個文件),即直接執(zhí)行.py(要作為module導(dǎo)入的這個文件)__name__保存的是一個非常固定的字符串,永遠(yuǎn)都是__main__。即print(__name__)得到的輸出結(jié)果是__main__。
如果將.py作為模塊導(dǎo)入之后,在導(dǎo)入之后的當(dāng)前的文件下進(jìn)行打印輸出就是模塊名。
所以怎么判斷.py作為module內(nèi)的所有未縮進(jìn)的代碼,在作為模塊被導(dǎo)入的時候測試代碼是否需要被執(zhí)行呢?我們就可以通過判斷__name__這個屬性是否是__main__或者是模塊名來判斷進(jìn)行判斷。
4、package
包是一個目錄(directory)/(python package)。在包的目錄下必須要有一個特殊的文件__init__.py
比如有一個發(fā)布模塊的目錄,下面包含制作好的包,還需要在發(fā)布模塊這個目錄下建立一個setup.py文件,setup.py這個文件和你所制作完成的包同屬于發(fā)布模塊這個目錄下。setup.py這個文件的執(zhí)行必須要進(jìn)入終端(所有學(xué)習(xí)都是在ubuntu下安裝的pycharm),使用python的解釋器來執(zhí)行這個文件,不能在pycharm中執(zhí)行。
5、文件
計算機(jī)的CPU如果想要訪問保存在磁盤上的文件:第一步應(yīng)該將磁盤中的文件數(shù)據(jù)加載到內(nèi)存中,因為內(nèi)存的讀寫速度要比磁盤的讀寫速度快很多。
計算機(jī)能夠識別什么樣的文件數(shù)據(jù)?計算機(jī)中只能識別0101這種二進(jìn)制方式的數(shù)據(jù),所以我們保存在磁盤上的文件本質(zhì)上都是以二進(jìn)制的方式來保存的。
但是在我們?nèi)粘J褂弥型ǔ盐募譃閮煞N類型:第一種叫做文本文件;第二種叫做二進(jìn)制文件。
所謂文本文件就是可以使用文本編輯軟件直接查看文件內(nèi)容的文件,我們就把他叫做文本文件。比如我們使用python開發(fā)的所有源程序是都可以直接查看內(nèi)容的,我們就把這種文件叫做文本文件。但是文本文件本質(zhì)上還是一個二進(jìn)制文件;
那么我們平時所說的二進(jìn)制文件是指:我們會把圖片文件,音頻文件,視頻文件等這些文件統(tǒng)稱為二進(jìn)制文件。之所以叫做二進(jìn)制文件是因為我們不能夠直接使用文本編輯軟件來查看這些文件的內(nèi)容,因為這些文件是需要使用其他專門的軟件來打開的。
讀就是將文件在磁盤中的數(shù)據(jù)加載到內(nèi)存;而寫就是把內(nèi)存中的內(nèi)容再重新寫回到磁盤文件。
??
文本文件中的每一個字符到底是怎樣用二進(jìn)制來表示的呢?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的python基础知识整理 第七节:单例设计模式、异常、模块、包、制作模块、文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python基础知识整理 第六节:面向对
- 下一篇: Pytorch的神经网络编程学习第一节