Python中if __name__ == '__main__',__init__和self 的解析

文章推薦指數: 80 %
投票人數:10人

Python中if __name__ == '__main__',__init__和self 的解析 ... 不管是直接執行還是被匯入,.py檔案的最頂層程式碼都會被執行(Python用縮排來區分 ... MdEditor Python中if__name__=='__main__',__init__和self的解析 語言:CN/TW/HK 時間 2020-09-2919:25:26 洋仔 主題: 掘金 稀土 Vue.js 微信小程式 Kotlin RxJava ReactNative Wireshark 敏捷開發 Bootstrap OKHttp 正則表示式 WebGL Webpack Docker MVVM 文章主要包括2部分內容,分別是ifname=='main'的解析和init與self的解析。

目錄 1ifname=='main' 1.1摘要 1.2程式入口 1.2.1一個.py檔案被其他.py檔案引用 1.2.2修改const.py,新增ifname=="main" 2init與self 2.1Python中self的含義 2.2Python中為何要有self 2.3首先來看一下init()和self物件 2.4如果沒有在init中初始化對應的例項變數的話,導致後續引用例項變數會出錯 2.5在函式中,使用對應的變數,雖然程式碼是可以執行的,但是實際上使用的,不是例項中的變數 1ifname=='main' 1.1摘要 通俗的理解name=='main':假如你叫小明.py,在朋友眼中,你是小明(name=='小明');在你自己眼中,你是你自己(name=='main')。

ifname=='main'的意思是:當.py檔案被直接執行時,ifname=='main'之下的程式碼塊將被執行;當.py檔案以模組形式被匯入時,ifname=='main'之下的程式碼塊不被執行。

1.2程式入口 對於很多程式語言來說,程式都必須要有一個入口,比如C,C++,以及完全面向物件的程式語言Java,C#等。

如果你接觸過這些語言,對於程式入口這個概念應該很好理解,C,C++都需要有一個main函式作為程式的入口,也就是程式的執行會從main函式開始。

同樣,Java,C#必須要有一個包含Main方法的主類,作為程式入口。

而Python則不同,它屬於指令碼語言,不像編譯型語言那樣先將程式編譯成二進位制再執行,而是動態的逐行解釋執行。

也就是從指令碼第一行開始執行,沒有統一的入口。

一個Python原始碼檔案(.py)除了可以被直接執行外,還可以作為模組(也就是庫),被其他.py檔案匯入。

不管是直接執行還是被匯入,.py檔案的最頂層程式碼都會被執行(Python用縮排來區分程式碼層次),而當一個.py檔案作為模組被匯入時,我們可能不希望一部分程式碼被執行。

1.2.1一個.py檔案被其他.py檔案引用 假設我們有一個const.py檔案,內容如下: PI=3.14 defmain(): print("PI:",PI) main() 執行結果:PI:3.14 現在,我們寫一個用於計算圓面積的area.py檔案,area.py檔案需要用到const.py檔案中的PI變數。

從const.py中,我們把PI變數匯入area.py: fromconstimportPI defcalc_round_area(radius): returnPI*(radius**2) defmain(): print("roundarea:",calc_round_area(2)) main() ''' 執行結果: PI:3.14 roundarea:12.56 ''' 1.2.2修改const.py,新增ifname=="main" 我們看到const.py中的main函式也被運行了,實際上我們不希望它被執行,因為const.py提供的main函式只是為了測試常量定義。

這時ifname=='main'派上了用場,我們把const.py改一下,新增ifname=="main": PI=3.14 defmain(): print("PI:",PI) ifname=="main": main() 執行const.py,輸出如下: PI:3.14 執行area.py,輸出如下: roundarea:12.56 如上,我們可以看到ifname=='main'相當於Python模擬的程式入口,Python本身並沒有這麼規定,這只是一種編碼習慣。

由於模組之間相互引用,不同模組可能有這樣的定義,而程式入口只有一個。

到底哪個程式入口被選中,這取決於name的值。

2init與self 2.1Python中self的含義 self,英文單詞意思很明顯,表示自己,本身。

python的self,是個物件(Object),是當前類的例項。

2.2Python中為何要有self 那就是: 在類的程式碼(函式)中,需要訪問當前的例項中的變數和函式的,即,訪問Instance中的: 對應的變數(屬性,property):Instance.ProperyNam,去讀取之前的值和寫入新的值 呼叫對應函式(function):Instance.function(),即執行對應的動作 ->而需要訪問例項的變數和呼叫例項的函式,當然需要對應的例項Instance物件本身 ->而Python中就規定好了,函式的第一個引數,就必須是例項物件本身,並且建議,約定俗成,把其名字寫為self ->所以,我們需要self 而如果沒有用到self,即程式碼中,去掉self後,那種寫法所使用到的變數,實際上不是你所希望的,不是真正的例項中的變數和函式,而是的訪問到了其他部分的變數和函數了。

甚至會由於沒有合適的初始化例項變數,而導致後續無法訪問的錯誤。

下面,就通過程式碼,來演示,如果去掉self,或者沒有合理的使用self,會出現哪些錯誤。

2.3首先來看一下init()和self物件 #!/usr/bin/envpython --coding:utf-8-- classPerson(object): definit(self,name,lang,website): self.name=name self.lang=lang self.website=website print('self:',self) print('typeofself:',type(self)) 複製程式碼 ''' 未例項化時,執行程式,構造方法沒有執行 ''' p=Person('Tim','English','www.universal.com') '''例項化後執行的結果 self: typeofself: ''' 可以看出self為例項變數p,是一個Person型別的物件。

classDog(object): definit(self,name,dog_type): self.name=name self.type=dog_type defsayhi(self): print("hello,Iamadog,mynameis",self.name) 複製程式碼 d=Dog('LiChuang',"京巴")#例項化 d.sayhi() 以下是d=Dog('LiChuang',"京巴")例項化的示意圖: 2.4如果沒有在init中初始化對應的例項變數的話,導致後續引用例項變數會出錯 如下程式碼,完整的演示了,如果沒有在類Class的最初的init函式中,正確的初始化例項變數,則會導致後續沒有變數可用,因而出現AttributeError的錯誤: #!/usr/bin/envpython --coding:utf-8-- name='wholeglobalname' ''' 注:此處全域性的變數名,寫成name,只是為了演示而用 實際上,好的程式設計風格,應該寫成gName之類的名字, 以表示該變數是Global的變數 ''' classPerson(object): definit(self,newPersonName): #self.name=newPersonName ''' 如果此處不寫成self.name 那麼此處的name,只是__init__函式中的區域性臨時變數name而已 和全域性中的name,沒有半毛錢關係 ''' name=newPersonName ''' 此處只是為了程式碼演示,而使用了局部變數name, 不過需要注意的是,此處很明顯,由於接下來的程式碼也沒有利用到此處的區域性變數name 則就導致了,此處的name變數,實際上被浪費了,根本沒有利用到 ''' defsayYourName(self): ''' 此處由於找不到例項中的name變數,所以會報錯: AttributeError:Personinstancehasnoattribute'name' ''' print('Mynameis%s'%self.name) 複製程式碼 defselfAndInitDemo(): personInstance=Person('Tim') personInstance.sayYourName() ifname=='main': selfAndInitDemo() '''未使用self.name時拋異常 Traceback(mostrecentcalllast): File"E:/python14_workspace/s14/day06/test_1.py",line18,in selfAndInitDemo() File"E:/python14_workspace/s14/day06/test_1.py",line15,inselfAndInitDemo personInstance.sayYourName() File"E:/python14_workspace/s14/day06/test_1.py",line11,insayYourName print('Mynameis%s'%self.name) AttributeError:'Person'objecthasnoattribute'name' ''' 從上述程式碼可見,由於在類的初始化(例項化)的init函式中,沒有給self.name設定值,使得例項中,根本沒有name這個變數,導致後續再去訪問self.name,就會出現AttributeError的錯誤了。

對應的,如果寫成self.name,則意思就正確了,就是初始化的時候,給例項中新增加,並且正常設定了正確的值newPersionName了,所以後續再去通過self.name,就可以訪問到,當前例項中正確的變數name了。

相應的正確寫法的程式碼如下: #!/usr/bin/envpython --coding:utf-8-- name='wholeglobalname' ''' 注:此處全域性的變數名,寫成name,只是為了演示而用 實際上,好的程式設計風格,應該寫成gName之類的名字, 以表示該變數是Global的變數 ''' classPerson(object): definit(self,newPersonName): self.name=newPersonName ''' 此處正確的,通過訪問self.name的形式,實現了: 1.給例項中,增加了name變數 2.並且給name賦了初值,為newPersionName ''' defsayYourName(self): ''' 此處由於開始正確的初始化了self物件,使得其中有了name變數, 所以此處可以正確訪問了name值了 ''' print('Mynameis%s'%self.name) defselfAndInitDemo(): personInstance=Person('Tim') personInstance.sayYourName() ifname=='main': selfAndInitDemo() '''MynameisTim''' 2.5在函式中,使用對應的變數,雖然程式碼是可以執行的,但是實際上使用的,不是例項中的變數 有時候,雖然你寫的程式碼,可以執行,但是使用到的變數,由於沒有加self,實際上是用到的不是例項的變數,而是其他的變數。

此類問題,主要和Python中的變數的作用域有關,但是此處例子中,也和是否使用self有關: #!/usr/bin/envpython --coding:utf-8-- name='wholeglobalname' ''' 注:此處全域性的變數名,寫成name,只是為了演示而用 實際上,好的程式設計風格,應該寫成gName之類的名字, 以表示該變數是Global的變數 ''' classPerson(object): name='classglobalname' def__init__(self,newPersonName): #self.name=newPersonName ''' 此處,沒有使用self.name 而使得此處的name,實際上仍是區域性變數name 雖然此處賦值了,但是後面沒有被利用到,屬於被浪費了的區域性變數name ''' name=newPersonName defsayYourName(self): ''' 此處,之所以沒有像之前一樣出現: AttributeError:Personinstancehasnoattribute'name' 那是因為,雖然當前的例項self中,沒有在__init__中初始化對應的name變數,例項self中沒有對應的name變數 但是由於例項所對應的類Person,有對應的name變數,所以也是可以正常執行程式碼的 對應的,此處的self.name,實際上是Person.name ''' print('Mynameis%s'%self.name) print('NamewithinclassPersonisactuallytheglobalname:%s'%name) print("OnlyaccessPerson'snameviaPerson.name=%s"%(Person.name)) 複製程式碼 defselfAndInitDemo(): personInstance=Person('Tim') personInstance.sayYourName() print('wholeglobalnameis%s'%name) ifname=='main': selfAndInitDemo() ''' Mynameisclassglobalname NamewithinclassPersonisactuallytheglobalname:wholeglobalname OnlyaccessPerson'snameviaPerson.name=classglobalname wholeglobalnameiswholeglobalname ''' 其中,可見,此處開始init中,沒有給self例項初始化對應的name, 而後面的函式sayYourName中,雖然可以呼叫到self.name而沒有出現AttributeError錯誤, 但是實際上此處的值,不是所期望的,傳入的name,即"Tim",而是類中的name的值,即"classglobalname"。

「其他文章」 git基本原理詳解 @StateObject和@ObservedObject的區別和使用 SwiftProtobuf的源頭Protobuf是什麼 SwiftUI-DataBinding註解 講講SwiftUI的資料流向,@State,@Binding的區別 ReactNative執行原理解析 圖解JanusGraph系列-JanusGraph指標監控報警(MonitoringJanusGraph) 圖解JanusGraph系列-JanusGraph指標監控報警(MonitoringJanusGraph 程式設計之美!從執行緒池狀態管理來看二進位制操作之美 程式設計之美!從執行緒池狀態管理來看二進位制操作之美 圖解JanusGraph系列-關於JanusGraph圖資料批量快速匯入的方案和想法(bulkloaddata) 圖解Janusgraph系列-圖資料底層序列化原始碼分析(DataSerialize) 圖解Janusgraph系列-併發安全:鎖機制(本地鎖分散式鎖)分析 圖解Janusgraph系列-併發安全:鎖機制(本地鎖分散式鎖)分析 Webpack構建工具 Python中if__name__=='__main__',__init__和self的解析 Flask-SQLAlchemy詳解 「掘金」 商用清潔機器人江湖:16位創業者「同臺競技」 功能管理(Featuremanagement)中的Keystone模式 美團簡單版動態執行緒池原始碼實現 基於SvelteUi中後臺解決方案SvelteAdmin 記一次圖片中繁體文字轉簡體的嘗試 復刻一個羊了個羊掘金商城版 Elasticsearch:分詞器中的token過濾器使用示例 終於,掘金也有人講傅立葉變換了 【melonJS】幾十行JS程式碼簡單編寫一個小遊戲「尋找掘金醬」 神馬?要退役JavaScript?!誰人出此狂言?! 「稀土」 再被拒,就不禮貌了:《非正式面試》第一期上線!陪你度過秋招季 功能管理(Featuremanagement)中的Keystone模式 美團簡單版動態執行緒池原始碼實現 基於SvelteUi中後臺解決方案SvelteAdmin 記一次圖片中繁體文字轉簡體的嘗試 Elasticsearch:分詞器中的token過濾器使用示例 如果稀土掘金App要更新“釋出文章”功能,那麼入口會設定在哪裡? 企業級GIT分支管控方案 [極致使用者體驗]讓你的網頁,適配微信大字號模式!體驗超好,快來收藏 英特爾XDC2022精彩回顧:共建開放生態,釋放“基建”潛能



請為這篇文章評分?