python模塊詳解
使用python時,常常會涉及到庫的調用,這就需要掌握模塊的基本知識。
本文分為如下幾個部分
- 概念說明
- 模塊的簡單調用
- 包的導入
- 特殊的
__init__.py
文件 - 導入模塊的搜索路徑
__all__
- 絕對引用與相對引用
- import運行本質
if __name__ == __main__
概念說明
這裡釐清python中模塊、庫、包之間的概念差異
- 模塊(module)其實就是py文件,裡面定義了一些函數、類、變數等
- 包(package)是多個模塊的聚合體形成的文件夾,裡面可以是多個py文件,也可以嵌套文件夾
- 庫是參考其他編程語言的說法,是指完成一定功能的代碼集合,在python中的形式就是模塊和包
模塊的簡單調用
比如我們有一個trymodule
的文件夾,裡面有一個first.py
文件,文件中的內容如下
a = 1def myfun(s): print(s + 1)
在trymodule
的文件夾下打開命令行窗口(按住shift單擊滑鼠右鍵,選擇「在此處打開命令窗口」),輸入python
進入命令行交互模式
>>> import first>>> aTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name a is not defined>>> first.a1>>> first.myfun(2)3
所以說first.py文件就是一個模塊,可以用import
導入,裡面變數都要用first.
前綴來引用,如果想不使用這個前綴可以這樣
>>> from first import a>>> a1
其他用法如下
# 重命名>>> from first import myfun as addone>>> addone(4)5# 導入模塊中全部變數>>> from first import *>>> myfun(2)3# 一次導入多個變數>>> from first import a, myfun>>> a1
包的導入
在trymodule文件夾中新建folder1
文件夾,我們想讓folder1
文件夾成為一個包。文件夾里新建abcd.py
文件,文件中內容如下
b = 2class Myclass: def __init__(self, name, age): self.name = name self.age = age def get_info(self): print(my name is {name} and age is {age}.format(name = self.name, age = self.age))
此時在folder1
文件夾中新建一個__init__.py
文件,否則程序會將這個文件夾當成普通文件夾來處理而不是一個包。這個__init__.py
文件中可以什麼都不填。
此時文件結構如下
trymodule│ first.py├───folder1│ │ abcd.py│ │ __init__.py
我們還是在trymodule
文件夾下打開命令行,進入python交互模式
我們來看一下下面幾種導入方式
>>> import folder1>>> folder1.abcd.bTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: module folder1 has no attribute abcd>>> from folder1 import abcd>>> bob = abcd.Myclass(name = Bob, age = 20)>>> bob.nameBob>>> bob.get_info()my name is Bob and age is 20>>> from folder1.abcd import b>>> b2>>> import folder1.abcd>>> abcd.bTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name abcd is not defined>>> folder1.abcd.b2>>> import folder1.abcd as aa>>> aa.b2
注意:
- 只是導入包不能隨便使用其中的模塊,要導入到具體模塊或者變數的層次
- 文件夾與文件之間可以用
.
也可以用from import
格式,而文件與裡面的變數之間只能用from import
格式,即不能import folder1.abcd.b
特殊的__init__.py
文件
__init__.py
文件其實是一個特殊的文件,它相當於名為folder1模塊,即如果使用import folder1
則可以調用在__init__.py
文件文件中定義的變數。
將__init__.py
文件編寫如下
from folder1.abcd import bc = 3
在trymodule文件夾下打開命令行,進入python交互模式
>>> import folder1>>> folder1.c3>>> folder1.b2>>> from folder1 import b>>> b2
對比之前的from folder1.abcd import b
,使用__init__.py
文件可以將常用的一些變數導入以方便調用。
另外需要注意兩點
__init__.py
文件編寫時,如果要導入其他模塊中的變數,即使__init__.py
文件和abcd.py
文件在同一個文件夾下,也不能from abcd import b
,要從abcd文件從哪裡來的開始寫,即從包的名稱開始。- folder1文件夾里的嵌套文件夾內不需要新建
__init__.py
文件即可像模塊一樣調用,但是一般還是要新建這個文件,可以方便地導入常用變數。
導入模塊的搜索路徑
用import hello
時,python會搜尋hello.py
文件,搜索順序如下
- 首先搜尋內置模塊是否有
hello
(所以我們定義的模塊名不要和內置模塊相同) - 如果內置模塊沒有,則看下面這些目錄里有沒有
>>> import sys>>> sys.path[, C:\Program Files\Anaconda3\python35.zip, C:\Program Files\Anaconda3\DLLs, C:\Program Files\Anaconda3\lib, C:\Program Files\Anaconda3, C:\Program Files\Anaconda3\lib\site-packages, C:\Program Files\Anaconda3\lib\site-packages\Sphinx-1.4.6-py3.5.egg, C:\Program Files\Anaconda3\lib\site-packages\snownlp-0.12.3-py3.5.egg, C:\Program Files\Anaconda3\lib\site-packages\win32, C:\Program Files\Anaconda3\lib\site-packages\win32\lib, C:\Program Files\Anaconda3\lib\site-packages\Pythonwin, C:\Program Files\Anaconda3\lib\site-packages\setuptools-27.2.0-py3.5.egg]
其中第一個表示當前的工作路徑,我們可以看出安裝的第三方包所在路徑(
C:\Program Files\Anaconda3\lib\site-packages
)也在這個列表之中,所以無論工作路徑在哪裡,都能搜尋到這些包。
如果想添加搜索路徑,可以參考這篇文章
__all__
首先要明確,import *
的方式無法導入以下劃線開頭的變數名
__init__.py
文件內容更改如下
from folder1.abcd import bc = 3_e = 4
python交互模式下
>>> from folder1 import *>>> c3>>> _eTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name _e is not defined
而如果指定導入是可以的
>>> from folder1 import c>>> c3>>> from folder1 import _e>>> _e4
如果定義了__all__
,則import *
就可以導入下劃線開頭的變數
__init__.py
文件內容更改如下
from folder1.abcd import b__all__ = [c, _e]c = b + 1_e = 4
python交互模式下
>>> from folder1 import *>>> bTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name b is not defined>>> c3>>> _e4
可見import *
只會導入__all__
中指定的變數,無論是否以下劃線開頭。這樣限制可以防止import *
命令導入太多變數污染命名空間,過濾掉一些中間變數如b
絕對引用與相對引用
python中的import
分為絕對引用和相對引用兩種。它們之間的差異在於,引用模塊時 定位被引用模塊位置 的方式不同
- 絕對引用是明確指定最高級文件(夾),文件之間用
.
連接,依次下來達到待引用模塊。我們上面的所有用法都屬於絕對引用。 - 而相對引用是 指定待引用模塊與當前文件的相對位置,
.
表示上一級文件
在這樣的文件結構下
trymodule│ first.py├───folder1│ │ abcd.py│ │ __init__.py
編寫__init__.py
文件,其中要引用abcd.py
文件中的變數
- 絕對引用是
from folder1.abcd import b
- 相對引用是
from .abcd import b
相對引用中,.
是指父文件(也有from . import xxx
的用法),.xxx
是指同一層文件,..xxx
則是與父文件夾同級的xxx
文件(多一個.
表示多往上一層)
一般用哪個呢?
python3之後官方推薦用絕對引用的方式,只有當模塊中文件關係非常複雜時相對引用才會有優勢。
import運行本質
使用import
語句,要明確兩件事
(1)執行導入模塊命令時,會首先檢查待導入的模塊是否在當前已有模塊之中,如果有則跳過import
。因此模塊之間相互引用不會導致無限循環。
查看當前已導入模塊使用下面方法
import syssys.modules
得到結果是一個字典,鍵是模塊名,值是文件所在路徑
(2)import
語句與文件執行
在這樣的文件結構下
trymodule│ first.py├───folder1│ │ abcd.py│ │ __init__.py
folder1是一個package,abcd是一個module
import folder1
只是導入package,相當於執行__init__.py
文件from folder import abcd
則執行了__init__.py
文件文件與abcd.py
文件from folder1.abcd import b
其實也執行了__init__.py
文件文件與abcd.py
文件
(要知道執行了什麼,可以在這些文件之中添加print
語句,看是否列印出結果)
知道這個執行原理,可以更好理解前面得到的一些結論
- 首先是在
__init__.py
文件中什麼都沒有的情況下,import folder1
無法調用abcd
模塊中的變數,是因為相當與運行了一個空文件,沒有將整個包導入工作空間 abcd
模塊中定義了print
語句後,import
兩次,只有第一次會print
出值,說明第二次檢查出模塊已在導入之列,忽略了這條import
命令
更多運行細節可以參考這篇文章
if __name__ == __main__
我們經常會在別人的代碼中發現if __name__ == __main__
,為了理解它的作用,我們來看下面的例子
在folder1文件夾下新建new.py文件,裡面內容為
print(__name__)
在folder1文件夾下打開命令行,輸入
python new.py
返回結果是__main__
在trymodule文件夾下打開命令行,進入python交互模式
>>> from folder1 import newfolder1.new>>> print(__name__)__main__>>> print(new.__name__)folder1.new
上面測試結果說明直接運行文件和import
文件是有差異的,差異在於二者的__name__
變數不同。__name__
變數是一個特殊的變數,每個py文件運行時都會對應一個__name__
變數,即使在交互模式下也可以查看這個變數值。
所以if __name__ == __main__
的作用就很好理解了,即import
時不執行下面的代碼,只有在直接執行這個文件時才運行之後的代碼。這算是一種約定俗成的寫法,如果不怕文件被import
,可以不用這個。
專欄信息
專欄主頁:python編程
專欄目錄:目錄
版本說明:軟體及包版本說明
推薦閱讀: