寫 Python 腳本,一定要加上這個!

大家好,我是菜鳥哥。
使用 Python 的人,平時經(jīng)常會寫一些腳本,不管是為了提升工作效率,還是為了滿足一些特定的需求,Python 腳本都是一個常見又有用的東西。
但是,我最近發(fā)現(xiàn)了一個以前不曾察覺的問題,就是腳本里面是否添加 if __name__ == "__main__": 這個語句,對腳本的使用其實是有很大影響的,并且這里面還有很大的學(xué)問。
常見誤區(qū)
很多朋友在寫腳本時比較隨意,簡單的腳本直接一溜寫下來,沒有函數(shù),順序執(zhí)行。復(fù)雜點的腳本,可能會加函數(shù)。這種寫法可讀性比較差,經(jīng)常讓人一眼找不到程序運行的入口和順序。
而 Python 社區(qū)比較推薦的寫法是在寫腳本時,加上下面這個語句:
def?main():
????#?do?something
????print("do?something.")
if?__name__?==?"__main__":
????main()
大多數(shù)人看到這里,會不會說,這有什么,加不加這個沒那么重要吧!
先不要忙著不屑,讓我們一起來仔細掰扯掰扯!
有什么用
在具體說明 if __name__ == '__main__' 的作用前,先從一個簡單的實例直觀上感受一下。
#?const.py
?
PI?=?3.14
?
def?train():
????print("PI:",?PI)
?
train()
#?area.py
?
from?const?import?PI
?
def?calc_round_area(radius):
????return?PI?*?(radius?**?2)
?
def?calculate():
????print("round?area:?",?calc_round_area(2))
?
calculate()
我們看下 area.py 的運行結(jié)果:
PI:?3.14
round?area:??12.56
的 PI 變量,在運行的時候,const.py 中函數(shù) train() 中的打印也帶過來了,而我們只是引用變量,并沒有引用函數(shù),所以這是我們不愿意看到的。
解決這個問題的方法也很簡單,我們只需在 const.py 中加上一句:
PI?=?3.14
def?train():
???print("PI:",?PI)
if?__name__?==?"__main__":
???train()
再次運行 area.py ,輸出結(jié)果如下:
round?area:??12.56
這是我們預(yù)期的結(jié)果。
程序運行入口
叢上述實例可以發(fā)現(xiàn),如果沒有 if __name__=="__main__": ,作為 area.py 導(dǎo)入文件時 const.py 中的所有代碼都被執(zhí)行了,而加上之后就只運行導(dǎo)入的部分代碼。
這就是 if __name__=="__main__": 顯而易見的作用,實際上 if __name__=="__main__": 就相當于是 Python 模擬的程序入口。由于模塊之間相互引用,不同模塊可能都有這樣的定義,而入口程序只能有一個,選中哪個入口程序取決于 __name__ 的值。
我們再來看一個小程序:
#?test.py
print("look?here")
print(__name__)
?
if?__name__?==?'__main__':
????print("I'm?test.py")
程序的運行結(jié)果如下:
look?here
__main__
I'm?test.py
可以發(fā)現(xiàn),此時變量 __name__ 的值為 __main__,所以打印 “I'm test.py”。如果運行其他文件,通過運行的文件調(diào)用本文件,則不會打印該語句,因為程序入口不對,該語句不執(zhí)行。
代碼規(guī)范
有了 if __name__=="__main__": 相當于 Python 程序也有了一個入口函數(shù),我們可以清晰的知道程序的邏輯開始于何處,當然還需要我們自覺的把程序的開始邏輯都放在這里。其實,這也是 PyCharm 推薦的作法。
為什么很多優(yōu)秀的編程語言,比如 C、Java、Golang、C++ 都有一個 main 入口函數(shù)呢?我想很重要的一個原因就是就是程序入口統(tǒng)一,容易閱讀。
多進程場景大作用
如果你用多進程來做并行計算,類似這樣的代碼:
import?multiprocessing?as?mp
def?useful_function(x):
????return?x?*?x
print("processing?in?parallel")
with?mp.Pool()?as?p:
????results?=?p.map(useful_function,?[1,?2,?3,?4])
????print(results)
運行這段代碼,控制臺會一直打印:
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
processing?in?parallel
并且程序會不停的報錯 RuntimeError。
如果你加上了 if __name__=="__main__": ,程序就會按照預(yù)期的進行:
import?multiprocessing?as?mp
def?useful_function(x):
????return?x?*?x
if?__name__?==?'__main__':
????print("processing?in?parallel")
????with?mp.Pool()?as?p:
????????results?=?p.map(useful_function,?[1,?2,?3,?4])
????????print(results)
Python 的多程序就是啟動了多個 Python 解器器,每個 Python 解釋器都會導(dǎo)入你這個腳本,復(fù)制一份全局變量和函數(shù)給子進程用,如果有了 if __name__=="__main__":,那它后面的代碼就不會被 import,也就不會被重復(fù)執(zhí)行。否則,這個創(chuàng)建多進程的代碼就會被 import,就會被執(zhí)行,從而無限遞歸的去創(chuàng)建子進程
總結(jié)
if __name__=="__main__": 雖然不是強制的,但是我強列推薦你寫腳本時按照這個規(guī)范來做,它是 Python 社區(qū)的約定,對應(yīng)Python 之禪:明確優(yōu)于隱晦。
推薦閱讀:
入門:?最全的零基礎(chǔ)學(xué)Python的問題? |?零基礎(chǔ)學(xué)了8個月的Python??|?實戰(zhàn)項目?|學(xué)Python就是這條捷徑
干貨:爬取豆瓣短評,電影《后來的我們》?|?38年NBA最佳球員分析?|? ?從萬眾期待到口碑撲街!唐探3令人失望? |?笑看新倚天屠龍記?|?燈謎答題王?|用Python做個海量小姐姐素描圖?|碟中諜這么火,我用機器學(xué)習(xí)做個迷你推薦系統(tǒng)電影
趣味:彈球游戲? |?九宮格? |?漂亮的花?|?兩百行Python《天天酷跑》游戲!
AI:?會做詩的機器人?|?給圖片上色?|?預(yù)測收入?|?碟中諜這么火,我用機器學(xué)習(xí)做個迷你推薦系統(tǒng)電影
小工具:?Pdf轉(zhuǎn)Word,輕松搞定表格和水印!?|?一鍵把html網(wǎng)頁保存為pdf!|??再見PDF提取收費!?|?用90行代碼打造最強PDF轉(zhuǎn)換器,word、PPT、excel、markdown、html一鍵轉(zhuǎn)換?|?制作一款釘釘?shù)蛢r機票提示器!?|60行代碼做了一個語音壁紙切換器天天看小姐姐!|
年度爆款文案
6).30個Python奇淫技巧集?
點閱讀原文,看B站我的20個視頻!

