Python基礎16-模塊與包基礎01

目錄

初識模塊和包

Python常用的內置模塊

關鍵字import和from

import、from查找的路徑

如何調用

 __name__與模塊執行

 __name__的用法(單元測試)


初識模塊和包

我們把功能相近或相關的py文件組成模塊,這樣分開寫代碼便於維護,形成公用的模塊避免重複實現。我們已經用到過time、functools、os、sys、cv2等。

模塊分爲三類,根據來源的“你我他”分爲以下三類:

  1. Python內置模塊,稱其爲第二人稱“你的”模塊,安裝了Python就有的模塊。
  2. 第三方模塊,稱其爲第三人稱“他的”模塊。用pip安裝第三方模塊,實際上和內置模塊沒太大區別,安裝了就變成了“內置”的了。請參考AI基礎02-CV基本操作1裏面pip的操作。
  3. 自定義模塊,也就是第一人稱“我的”模塊。我的地盤聽我的。

模塊是可以被導入的,用import,在前面的博客中曾經from functools import reduce。

回憶在Java裏面的包,實際上就是.class所在的文件夾。Python裏面並非如此,初識Python包的時候,先記住一個特徵,後面再仔細研究。如果文件夾裏面有__init__.py的空文件,那麼這個文件夾就是個包。否則這個文件夾就只是個文件夾。包可以用來組成模塊,這樣可以更好的組織代碼,避免名字衝突。

Python常用的內置模塊

Python常用的內置模塊有time、random、os(操作系統相關)、sys(解釋器相關)、json、pickle、logging(日誌)、re(正則表達式)等。後面一個一個學習。

關鍵字import和from

import都幹了些什麼?from...import又會幹些什麼?

import會做以下事情:

  1. 被import的文件從頭到尾執行一遍
  2. 引入變量名到當前文件,僅僅引入import後面的那個變量名

我們用一個實驗來說明,在一個文件夾下創建三個py文件,__init__.py、test.py、calc.py內容如下,執行test.py以後,發現calc.py中的兩個print都執行了。說明import時候,被import的py文件從頭到尾執行了一遍。引入的變量calc,通過calc可以調用add和sub兩個函數。

# test.py
import calc

print(calc.add(3, 5))
print(calc.sub(3, 5))
# from calc begin
# from calc end
# 8
# -2
# calc.py
print('from calc begin')


def add(x, y):
    return x + y


def sub(x, y):
    return x - y

print('from calc end')

 我們還可以from ... import xxx,import還是會把被import文件從頭到尾執行一遍,但是引入的變量只是import後面的那個變量。如果想全部引入,可以from ... import *,但是並不推薦這樣做,因爲引入的多餘的對象會讓代碼看起來產生歧義,引發更多人爲造成的錯誤。所以,用什麼就import什麼是比較好的習慣,就像前面博客裏from functools import reduce,用了reduce就只引入reduce。

# test.py
from calc import add

print(add(3, 5))
# from calc begin
# from calc end
# 8

import、from查找的路徑

上面的例子,可以找到calc是因爲calc是因爲calc和test在同一層級。我們改變一下calc的位置,新建一個包就叫my_module,將calc放進my_module裏面,執行上面的代碼,會報錯找不到calc。那麼Python是怎麼找到被引入的模塊的呢?Python是從sys.path裏面找到的。程序開始執行前,會把py文件的當前路徑放進sys.path裏面,之後所有的import都在這個sys.path裏面找,和sys.path的子目錄沒有關係。

我們重新調整一下結構,程序入口bin.py,邏輯在main.py,被使用的模塊放在calc.py裏面。由於被執行的程序是bin.py,所以在sys.path裏面加入的是bin.py所在的目錄,之後程序不管執行到哪裏,import的時候都會去sys.path的目錄去找被引入的模塊。main.py裏面引入calc,如果直接寫import calc,在sys.path中的d:/dev/day21裏面是找不到calc.py的。因爲正確的寫法是from my_module import calc。

# calc.py
def add(x, y):
    return x + y


def sub(x, y):
    return x - y
# main.py
from my_module import calc


# 由於被執行的程序是bin.py,所以在sys.path裏面加入的是bin.py所在的目錄
# 之後程序不管執行到哪裏,import的時候都會去sys.path的目錄去找被引入的模塊
# main.py裏面引入calc,如果直接寫import calc,在sys.path中的d:/dev/day21裏面是找不到calc.py的
# 因此正確的寫法是from my_module import calc。

def run():
    print(calc.add(3, 5))
# bin.py
from my_module import main

main.run()
# 8

如何調用

當我們在bin.py裏面就是要直接使用calc的add函數怎麼辦呢?我們可以用這種“點”的方式,找到對應模塊、包的路徑。我們重新調整一下,創建包web1、web2、web3,web3下有模塊calc。

# web1.web2.web3.calc.py
def add(x, y):
    return x + y


def sub(x, y):
    return x - y


# print(__name__)
# bin.py
from web1.web2.web3.calc import add

print(add(3, 8))
# 11

 __name__與模塊執行

__name__是Python內置的一個變量。如果模塊被直接執行,當模塊的__name__的值是'__main__'。如果模塊被import,那麼模塊的__name__的值是模塊的路徑(希望我這麼不太準確的描述沒有問題)。我們以如何調用這一節爲例,在web1.web2.web3.calc.py裏面加一行代碼打印__name__的值。

如果我們直接執行calc.py,那麼打印出來的就是__main__。

如果我們執行bin.py,那麼打印出來的就是web1.web2.web3.calc。

# web1.web2.web3.calc.py
def add(x, y):
    return x + y


def sub(x, y):
    return x - y


print(__name__)
# 直接執行calc,那麼calc裏面的__name__的值是__main__
# bin.py
from web1.web2.web3.calc import add

print(add(3, 8))
# 11
# 如果執行bin.py,裏面import calc,那麼calc裏面的__name__的值是web1.web2.web3.calc

 __name__的用法(單元測試)

根據上一節所述的__name__的值,我們應該在每個py文件被執行的代碼前面加上if __name__ == '__main__'判斷。

這樣,模塊自身被執行的代碼,只有在自己被直接執行(單元測試)的時候才被執行,被import的時候不會被執行,這是用戶希望的那樣。這個用法和Java裏每個類的main方法的用法有些類似。從現在起,養成好習慣,在每個py文件裏面自覺加上if __name__ == '__main__'判斷。

print(__name__)
if __name__ == '__main__':
    print('寫單元測試代碼')

 

next

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章