前言
最近在組內研究專項項目,其中的一個現有工具是用 Python 開發的,我的目標是對這款工具的流程進行最佳化。雖然可以找到對應的開發者了解現有流程,然後結合我的研究提出最佳化方案,最後讓 TA 去編碼實作。但是程式設計師心理使然,什麼東西都想自己琢磨明白,於是開啟了摸索歷程。
上網搜尋資料,下載了 PyCharm 開發工具,進行了一些環境配置,於是乎就開工了。由於之前沒有接觸過 Python 語言,打開程式碼資料夾就蒙圈了,只見一大堆 .py 檔案,不知道從哪裡下手。本人 C# 出身,寫過少許 C/C++,所以一直想著有個類似 Main() 函數的東西是整個程式的進入點。然而,查遍了整個目錄,沒有找到任何線索,接下來就開始各種研究。
需要說明的是,本文僅是一隻 Python 新手的學習筆記,並不一定正確或完整,歡迎大家指正。 每每接觸新工具或新語言,都有一種莫名的喜悅,樂於用舊知識來推敲,故而記錄下來。
順序執行
在 Python 世界中,每一個 .py 檔案就是一個模組,在主控台中輸入檔名即可呼叫該模組。 模組有些類似於批次檔(.bat),其中的陳述句是按順序執行的。 這點和我最初的想像不一致,總想著它和 C# 等語言一樣,檔案中應該由類別來組織,實則不然。
首先,在 D 槽根目錄建立一個名為 Test1.py 的檔案,內容如下:
print("Test1 First")
print("Test1 Second")
然後,轉到主控台,將目錄切換到 D 槽,啟動 Test1.py 模組,結果如下:
D:\>python Test1.py
Test1 First
Test1 Second
嗯,不錯,完全符合預期,再試一下模組間呼叫。 在 D 槽中建立 Test2.py 檔案,在其中呼叫 Test1.py 模組:
import Test1
print("Test2 First")
print("Test2 Second")
在主控台中啟動 Test2.py,輸出結果:
D:\>python Test2.py
Test1 First
Test1 Second
Test2 First
Test2 Second
可以理解的是,在 Test2.py 檔案中, import Test1 陳述句在前面,所以在匯入 Test1 模組時便執行了其中的陳述句,因此 Test1 中的輸出在前面。
如果將 import Test1 放在後面, Test1 的輸出也會出現在後面:
print("Test2 First")
print("Test2 Second")
import Test1
D:\>python Test2.py
Test2 First
Test2 Second
Test1 First
Test1 Second
函數定義
模組中的程式碼能否更加靈活?除了按順序執行,還可以根據需要呼叫,就像 C# 語言中的函數那樣。 上文中的 Print 應該就是一個內建函數,查資料,找到 Python 中函數的定義:
def 函數名(參數列表):
函數體
趕緊試一下,在 Test1.py 中定義一個 SayHello 函數:
print("Test1 First")
print("Test1 Second")
def SayHello():
print("Hello World")
SayHello()
print("Test1 Third")
輸出結果:
D:\>python Test1.py
Test1 First
Test1 Second
Hello World
Test1 Third
嗯,符合預期,沒毛病,按順序執行。
如果只是定義 SayHello() 函數,而沒有呼叫的話,是不會有 Hello World 一行輸出的。
接下來,嘗試一下模組間函數的呼叫,修改 Test2.py 檔案:
import Test1
print("Test2 First")
print("Test2 Second")
Test1.SayHello()
輸出如下:
D:\>python Test2.py
Test1 First
Test1 Second
Hello World
Test1 Third
Test2 First
Test2 Second
Hello World
哈哈,對的,對的,最後一行的 Hello World 即是 Test2.py 中的 Test1.SayHello() 陳述句輸出的。 至於前面第三行的 Hello World 嘛,那是 import Test1 時由 Test1 模組輸出的。
__main__
了解了函數的定義及模組間的呼叫,隨之而來的疑惑是,程式\模組 的進入點在哪裡。
搜尋了一下資料,找到了 __name__ 屬性。先來測試一段程式碼,修改 Test1.py 檔案:
def SayHello():
print("Hello World")
def SayBye():
print("Bye World")
SayHello()
if(__name__=="__main__"):
print("Main")
SayBye()
在主控台中直接啟動 Test1.py:
D:\>python Test1.py
Hello World
Main
Bye World
嗯,還好理解,按順序執行的,且滿足了 if(__name__=="__main__") 條件,所以輸出了 Main。
且慢,換一種方式,透過 Test2.py 間接呼叫 Test1.py 試試,先修改 Test2.py 檔案:
import Test1
print("Test2 First")
print("Test2 Second")
然後啟動 Test2.py 檔案來看看結果:
D:\>python Test2.py
Hello World
Bye World
Test2 First
Test2 Second
怎麼沒有輸出 Main 呢?嗯,有點意思,找到 菜鳥教程 的解釋:
每個模組都有一個
__name__屬性,當其值是__main__時,表明該模組自身在執行,否則是被引入
這個 __name__ 屬性還好理解,模組的保留欄位(屬性),但是怎麼理解這個 __main__ 呢?
這裡的 __main__ 可能可以理解為程式的進入點函數,模組直接被進入點函數呼叫,則其 __name__ 屬性值為 main,否則為 模組檔名:
def SayHello():
print("Hello World")
def SayBye():
print("Bye World")
SayHello()
if(__name__=="__main__"):
print("Main")
else:
print(__name__)
SayBye()
D:\>python Test2.py
Hello World
Test1
Bye World
Test2 First
Test2 Second
總結
本文講了 Python 模組的一些基本特性,涉及到的知識非常粗淺,僅為記錄個人的學習過程。
每每接觸新工具或新語言,都有一種莫名的喜悅,樂於用舊知識來推敲,故而記錄下來。
最後,引用 菜鳥教程 關於 模組 的一些重要解釋:
- 模組除了方法定義,還可以包括可執行的程式碼。這些程式碼一般用來初始化這個模組。
- 一個模組只會被匯入一次,不管你執行了多少次 import。這樣可以防止匯入模組被一遍又一遍地執行。
- 模組是可以匯入其他模組的。在一個模組的最前面使用 import 來匯入一個模組,當然這只是一個慣例,而不是強制的。