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

2021-12-26 Python七號

我發現有不少朋友寫 Python 腳本非常隨意,要麼不用函數,要麼函數隨處定義,反正第一眼看不出要執行的第一行代碼位於何處,這樣的腳本可讀性很差,而且容易隱藏 bug,解決這個問題很簡單,當我們寫 Python 腳本時,一定要加上這個:

def main():
    # do something
    print("do something.")


if __name__ == "__main__":
    main()

你可能要反對了:我怎麼爽就怎麼寫,憑什麼聽你的,多寫個 if __name__...?

別急,讓我說三個原因。

第一,它讓 Python 文件的作用更加明確

首先需要明白 __name__ 的作用,當腳本直接被 Python 解釋器執行時,其值就是 "__main__",當其被其他 Python 程序 import 的時候,其值就是對應的 Python 腳本文件名,可以在 Python 解釋器驗證下,假定有個 some_script.py 其內容如下:

print("some_script.py")
print(__name__)

在 Python 解釋器導入一下:

❯ vim some_script.py
❯ python
Python 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import some_script
some_script.py
some_script
>>>

可以看到,__name__ 的值就是 Python 腳本的文件名 some_script。

也就是說 if __name__ == "__main__": 後面的代碼在 import 的時候是不會運行的。

明白了這一點,if __name__ == "__main__": 就可以做為區分腳本和庫的一個標誌,當我們看到 if __name__ == "__main__": 時,就認為這一個可以直接運行的腳本,當沒有看到這行代碼時,就認為這是一個庫,可以被其他程序引用,Explicit is better than implicit.,不是嗎?

再舉個例子:

假如你寫了一個不帶if __name__ == "__main__": 的腳本,叫 bad_script.py,內容如下:

def useful_function(x):
    return x * x


class UsefulClass:
    def __init__(self, x):
        self.x = x

#你自己測試了一吧,沒毛病
for i in range(7):
    print(useful_function(i))

別人寫了個 useful.py,引用了你的 useful_function:

from bad_script import useful_function


def main():
    print(f'{useful_function(3)=}')


if __name__ == '__main__':
    main()

一運行,發現列印了不可預期的內容,見下圖紅色部分:

查了半天原因,發現是你的腳本輸出的,你說別人會不會罵你?

假如你在自己腳本裡定義了全局變量,別人如果在不合適的位置導入了 *,就會把你這個全局變量也導入,導致變量覆蓋,很容易會出現 bug。

第二,它讓 Python 文件更加易讀,對 IDE 友好

有了 if __name__ == "__main__": 相當於 Python 程序也有了一個入口函數,所有的變量都從這裡開始定義和使用,我們可以清晰的知道程序的邏輯開始於何處(當然還需要我們自覺的把程序的開始邏輯都放在這裡)

其實,這也是 PyCharm 推薦的做法,當你新建一個項目的時候,它默認創建的 main.py 就是長這樣的:

在if __name__ == "__main__": 的那一行的最左邊也有一個綠色的運行按鈕,點擊一下,程序就從這一行開始運行了。

為什麼很多優秀的程式語言,比如 C、Java、Golang、C++ 都有一個 main 入口函數呢?我想很重要的一個原因就是就是程序入口統一,容易閱讀。

第三、多進程場景下,必須用 if main

比如說你用多進程搞並行計算,寫了這樣的代碼:

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)

當你運行的時候,會發現程序不停的在創建進程,同時也在不停的報錯 RuntimeError,即使你 Ctrl C 也無法終止程序。而加上了 if __name__ == "__main__": 程序就會按照預期的進行:

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 解釋器都會導入你這個腳本,複製一份全局變量和函數給子進程用,如果有了if __name__ == "__main__":,那它後面的代碼就不會被 import,也就不會被重複執行。否則,這個創建多進程的代碼就會被 import,就會被執行,從而無限遞歸的去創建子進程,Python3 會報 RuntimeError,順序是先創建進程,然後報錯的,因此就會出現不停的創建進程,不停的報錯,Ctrl C 也無法終止的現象,只能 kill 掉整個終端。這裡有個官方解釋[1]

最後的話

if __name__ == "__main__": 雖然不是強制的,但是基於上述三點原因,我強烈推薦你這麼做,它是 Python 社區的約定,對應Python 之禪:明確優於隱晦。正如 _ 作為變量名的意思就是告訴讀代碼的人:這個變量不重要,後面也不會用到它。當你看到 Python 腳本有 if __name__ == "__main__": 時,就會意識到,這是一個可執行的腳本,當被其他程序導入時,這部分代碼不會被執行,而多進程的程序中,這是必須的。

如果有收穫的話,歡迎點讚、關注、在看,感謝閱讀。

參考資料[1] 

官方解釋: https://docs.python.org/zh-cn/3/library/multiprocessing.html#programming-guidelines

相關焦點

  • 如何用python寫遊戲腳本?
    很多人學習python,不知道從何學起。很多人學習python,掌握了基本語法過後,不知道在哪裡尋找案例上手。很多已經做案例的人,卻不知道如何去學習更加高深的知識。那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視頻教程,電子書籍,以及課程的原始碼!
  • 你用 Python 寫過哪些牛逼的程序/腳本?
    因此,我寫了一個 python 腳本, 目的是為了使用 非官方的 IMDb API 來獲取數據。我選擇一個電影文件(文件夾),點擊右鍵,選擇『發送到』,然後 點擊 IMDB.cmd (順便提一下,IMDB.cmd 這個文件就是我寫的 python 腳本),就是這樣。
  • Python腳本計算RDF
    徑向分布函數rdf計算方法和程序在做化學鍵分析時經常會用到徑向分布函數RDF,為了省事,寫了個Python腳本快速計算出相應原子或離子的RDF。文獻中經常見到原子的徑向分布函數圖,是如何畫出的呢?本文將進行簡要介紹。圖片來源於Inorg. Chem. 2016, 55, 9, 4616-4625.
  • 用python寫遊戲腳本原來這麼簡單
    當然,作為一名程式設計師,肝這種東西完全可以用寫代碼的方式幫我們自動完成。遊戲腳本其實並不高深,最簡單的體驗方法就是下載一個Airtest了,直接截幾個圖片,寫幾層代碼,就可以按照自己的邏輯玩兒遊戲了。當然,本篇文章不是要講Airtest這個怎麼用,而是用原始的python+opencv來實現上面的操作。
  • Pyinstaller 打包Python腳本踩坑之旅
    Pyinstaller 打包Python腳本踩坑之旅 前言:眾所周知,python是一門強大的膠水語言,尤其憑藉其豐富的第三方庫近些年來十分火熱
  • 如何開始寫你的第一個python腳本——簡單爬蟲入門!
    大概是這樣的:with open(路徑以及文件名,保存模式) as f:f.write(數據)#如果是文本可直接寫入,如果是其他文件,數據為二進位模式更好當然保存到excel表格或者word文檔需要用到 xlwt庫(excel)、python-docx庫(word),這個在網上很多,大家可以自行去學習。
  • 利用Python進行遊戲腳本編程,不愧是最強的腳本語言!
    為什麼要使用腳本語言C++ 是一種強大的語言,並且是 C 語言的巨大改進,但它並不是完成所有任務的最佳選擇。C++ 非常強調運行時性能 [Stroustrup94],譬如,假如一個語言特性使得程序跑起來變慢,那麼這個特性便不會加入 C++ 語言中。C++ 程式設計師也因此背負了很多的限制和煩惱。
  • 性能工具之Jmeter腳本python啟動
    (users) :線程數,也就虛擬用戶數Ramp-uo Period(in seconds) :控制虛擬用戶啟動時間Loop Count:控制執行次數。python啟動Jmeter腳本python基礎知識複習os.getcwd: 得到當前工作目錄,即當前python腳本工作的目錄路徑。
  • 運行python腳本時傳入參數的三種方式
    如果在運行python腳本時需要傳入一些參數,例如gpus與batch_size,可以使用如下三種方式。 這三種格式對應不同的參數解析方式,分別為sys.argv、argparse、 tf.app.run, 前兩者是python自帶的功能,後者是tensorflow提供的便捷方式。
  • 使用 Python 進行遊戲腳本編程
    為什麼要使用腳本語言C++ 是一種強大的語言,並且是 C 語言的巨大改進,但它並不是完成所有任務的最佳選擇。C++ 非常強調運行時性能 [Stroustrup94],譬如,假如一個語言特性使得程序跑起來變慢,那麼這個特性便不會加入 C++ 語言中。C++ 程式設計師也因此背負了很多的限制和煩惱。
  • Maya藝術家的Python腳本
    要從命令提示符或終端窗口運行此腳本,請使用python的運行程序調用該腳本。python命令啟動Python解釋器,並使用解釋器運行給定腳本。當我們在Maya中時,Python解釋器已經在運行。要從Maya內部調用腳本和其他腳本,需要將其import。
  • 手把手帶你,用 Python 寫一個 Monkey 自動化測試腳本!!!
    之前講解了 Android Monkey 命令的使用方式,今天趁著還熱乎就手把手用 Monkey 寫一個壓力測試的腳本。還不了解什麼是 Monkey 的,可以看看之前的文章,《關於 Monkey ,你所需要知道的,都在這裡!!!》。
  • 被python的這個「特性」給坑死了
    我們知道字符串替換可以直接用replace方法,但這個方法只適合簡單的字符替換,就是前提你要明確知道你要替換什麼。例如把「java」去掉s = "java python"print(s.replace("java", "")) # python遇到複雜場景就不得不用正則表達式的方法來替換了。
  • 【python安全攻防:argparse模塊】python腳本接收命令行參數(結尾彩蛋哦)
    收錄於話題 #python1.創建ArgumentParser()對象2.調用add_argument()方法添加參數 3.使用parse_args()解析添加的參數簡單示例示例代碼:執行結果:
  • python將腳本與交互模式結合
    將腳本與交互模式結合也可以將腳本文件與交互模式結合起來,以將預先編寫的腳本合併到交互程序中。入門為了使用腳本文件,您必須為計算機準備使用它們,或者必須採用 稍後描述的 替代方法 之一 。python.exe的位置首次安裝Python軟體時,應該在硬碟驅動器上的某個位置創建一個目錄,其中包含一個名為 python.exe 的文件 。您將需要找到該文件。
  • Linux 平臺下 Python 腳本編程入門(一)
    眾所周知,系統管理員需要精通一門腳本語言,而且招聘機構列出的職位需求上也會這麼寫。
  • 為何要將Jupyter Notebook轉換為python腳本?
    圖源:unsplash一定有更好的方法來處理代碼,所以我決定嘗試一下腳本。例如,在通過上面的測試後,在運行腳本時仍然有一個類型錯誤,這使數據中有空值。那就只需要處理這個問題,就可以平穩運行代碼。當一些數據科學家建議將Notebook筆記本換成腳本從而避免上述一些問題時,我不理解也不願意這麼做,因為我不喜歡運行單元格時無法看到這種不確定性。但是,當我在新公司開始第一個真正的數據科學項目時,Jupyter Notebook的缺點越來越大,所以我決定踏出舒適區,用腳本進行實驗。
  • CTF 圖像隱寫Python腳本處理
    CTF中經常會遇到很多圖片的隱寫題目需要使用腳本來解題,最常用到的就是使用python中的PIL庫,所以如果要更好的解出圖片隱寫相關處理的題目,掌握好這個庫的使用是必要的。本期就來給大家介紹下這個庫的基本使用和幾道圖片題目的解題思路。
  • 用 Python 做個簡單的備份腳本程序
    程式設計師是個任性的群體,因為如果他經常在網絡找資源的話,會寫個腳本程序進行資源的抓取;如果系統自帶的一些軟體不好用,會自己寫個腳本程序,簡單好用…
  • 如何讓Python腳本變成Windows應用
    window下利用visual studio和cython編譯pyqt5腳本為