python模块讲解_python模块详解
使用python時,常常會涉及到庫的調用,這就需要掌握模塊的基本知識。
本文分為如下幾個部分概念說明
模塊的簡單調用
包的導入
特殊的__init__.py文件
導入模塊的搜索路徑
__all__
絕對引用與相對引用
import運行本質
if __name__ == '__main__'
概念說明
這里厘清python中模塊、庫、包之間的概念差異模塊(module)其實就是py文件,里面定義了一些函數、類、變量等
包(package)是多個模塊的聚合體形成的文件夾,里面可以是多個py文件,也可以嵌套文件夾
庫是參考其他編程語言的說法,是指完成一定功能的代碼集合,在python中的形式就是模塊和包
模塊的簡單調用
比如我們有一個trymodule的文件夾,里面有一個first.py文件,文件中的內容如下
a = 1
def myfun(s):
print(s + 1)
在trymodule的文件夾下打開命令行窗口(按住shift單擊鼠標右鍵,選擇“在此處打開命令窗口”),輸入python進入命令行交互模式
>>> import first
>>> a
Traceback (most recent call last):
File "", line 1, in
NameError: name 'a' is not defined
>>> first.a
1
>>> first.myfun(2)
3
所以說first.py文件就是一個模塊,可以用import導入,里面變量都要用first.前綴來引用,如果想不使用這個前綴可以這樣
>>> from first import a
>>> a
1
其他用法如下
# 重命名
>>> from first import myfun as addone
>>> addone(4)
5
# 導入模塊中全部變量
>>> from first import *
>>> myfun(2)
3
# 一次導入多個變量
>>> from first import a, myfun
>>> a
1
包的導入
在trymodule文件夾中新建folder1文件夾,我們想讓folder1文件夾成為一個包。文件夾里新建abcd.py文件,文件中內容如下
b = 2
class 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文件中可以什么都不填。
注:python3.3+已經可以省略掉空白的__init__.py 文件。
此時文件結構如下
trymodule
│ first.py
├───folder1
│ │ abcd.py
│ │ __init__.py
我們還是在trymodule文件夾下打開命令行,進入python交互模式
我們來看一下下面幾種導入方式
>>> import folder1
>>> folder1.abcd.b
Traceback (most recent call last):
File "", line 1, in
AttributeError: module 'folder1' has no attribute 'abcd'
>>> from folder1 import abcd
>>> bob = abcd.Myclass(name = 'Bob', age = 20)
>>> bob.name
'Bob'
>>> bob.get_info()
my name is Bob and age is 20
>>> from folder1.abcd import b
>>> b
2
>>> import folder1.abcd
>>> abcd.b
Traceback (most recent call last):
File "", line 1, in
NameError: name 'abcd' is not defined
>>> folder1.abcd.b
2
>>> import folder1.abcd as aa
>>> aa.b
2
注意:只是導入包不能隨便使用其中的模塊,要導入到具體模塊或者變量的層次
文件夾與文件之間可以用.也可以用from import格式,而文件與里面的變量之間只能用from import格式,即不能import folder1.abcd.b
特殊的__init__.py文件
__init__.py文件其實是一個特殊的文件,它相當于名為folder1模塊,即如果使用import folder1則可以調用在__init__.py文件文件中定義的變量。
將__init__.py文件編寫如下
from folder1.abcd import b
c = 3
在trymodule文件夾下打開命令行,進入python交互模式
>>> import folder1
>>> folder1.c
3
>>> folder1.b
2
>>> from folder1 import b
>>> b
2
對比之前的from folder1.abcd import b,使用__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 b
c = 3
_e = 4
python交互模式下
>>> from folder1 import *
>>> c
3
>>> _e
Traceback (most recent call last):
File "", line 1, in
NameError: name '_e' is not defined
而如果指定導入是可以的
>>> from folder1 import c
>>> c
3
>>> from folder1 import _e
>>> _e
4
如果定義了__all__,則import *就可以導入下劃線開頭的變量
__init__.py文件內容更改如下
from folder1.abcd import b
__all__ = ['c', '_e']
c = b + 1
_e = 4
python交互模式下
>>> from folder1 import *
>>> b
Traceback (most recent call last):
File "", line 1, in
NameError: name 'b' is not defined
>>> c
3
>>> _e
4
可見import *只會導入__all__中指定的變量,無論是否以下劃線開頭。這樣限制可以防止import *命令導入太多變量污染命名空間,過濾掉一些中間變量如b
絕對引用與相對引用
python中的import分為絕對引用和相對引用兩種。它們之間的差異在于,引用模塊時 定位被引用模塊位置 的方式不同絕對引用是通過.的連接,指定出最高級文件(夾),到目標文件的絕對路徑。我們上面的所有用法都屬于絕對引用。
而相對引用是 指定待引用模塊與當前文件的相對位置,.表示上一級文件
絕對引用類似這樣from folder.abcd import myclass
相對引用類似這樣from .abcd import myclass
在實際使用中,無論是絕對導入還是相對導入都要注意,如何導入與被調用位置有關。
以下面的文件結構為例
folder1
│ first1.py
│ first2.py
└─folder2
| second1.py
| second2.py
└─folder3
| third1.py
| third2.py
下面分為兩種情況
1.folder1是一個項目,運行這個項目需要在folder1文件夾中打開cmd,運行python first1.py
# first1.py
from first2 import sth # OK
from folder1.first2 import sth # ERROR
from .first2 import sth # ERROR
from folder2.second1 import sth # OK
# second1.py
from folder2.second2 import sth # OK
from .second2 import sth # OK
from second2 import sth # ERROR
(注意first1引用first2 與 second1引用second2 的區別)
2.folder1是一個包,一般使用時,是在外面的文件夾中import這個包
# first1.py
from folder1.first2 import sth # OK
from .first2 import sth # OK
from first2 import sth # ERROR
from . import first2 # OK
import .first2 # ERROR
from folder1.folder2 import second1 # OK
from .folder2 import second1 # OK
# second1.py
from folder1.folder2 import second2 # OK
from . import second2 # OK
from .. import first1 # OK
from ..folder3 import third1 # OK
規律絕對引用就是從包的位置一直往下,寫到目標文件位置
相對引用,用.代替當前文件所在目錄,用..代替再上一級目錄,用點來回溯,之后往下寫到目標文件位置。
.只能放在from后,不能放import后。
相對引用的好處在于,代碼中不需要出現folder1這個名稱,因此當包的名稱改變時,里面代碼不需要做任何改變;或者有的用戶要裝兩個版本的包,把其中一個版本的包重命名了,此時使用相對引用也不會出問題。
另外,以second1.py為例,如果其中有一些相對引用的代碼,在folder1的上一層文件夾調用
python folder1/folder2/second1.py
這時相當于在folder2文件夾中調用second1.py文件,會報錯。但如果像下面這樣就可以正常運行
python -m folder1.folder2.second1
import運行本質
使用import語句,要明確兩件事
(1)執行導入模塊命令時,會首先檢查待導入的模塊是否在當前已有模塊之中,如果有則跳過import。因此模塊之間相互引用不會導致無限循環。
查看當前已導入模塊使用下面方法
import sys
sys.modules
得到結果是一個字典,鍵是模塊名,值是文件所在路徑
(2)import語句與文件執行
在這樣的文件結構下
trymodule
│ first.py
├───folder1
│ │ abcd.py
│ │ __init__.py
folder1是一個package,abcd是一個moduleimport 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命令
一個例子import numpy as np,之后可以這樣調用np.random.normal()
但import skimage,不可以調用skimage.io.imread(),要import skimage.io才可以
這是因為numpy文件夾中的_init_.py文件中有一句from . import random;而skimage沒有
更多運行細節可以參考這篇文章
if __name__ == '__main__'
我們經常會在別人的代碼中發現if __name__ == '__main__',為了理解它的作用,我們來看下面的例子
在folder1文件夾下新建new.py文件,里面內容為
print(__name__)
在folder1文件夾下打開命令行,輸入
python new.py
返回結果是__main__
在trymodule文件夾下打開命令行,進入python交互模式
>>> from folder1 import new
folder1.new
>>> print(__name__)
__main__
>>> print(new.__name__)
folder1.new
上面測試結果說明直接運行文件和import文件是有差異的,差異在于二者的__name__變量不同。__name__變量是一個特殊的變量,每個py文件運行時都會對應一個__name__變量,即使在交互模式下也可以查看這個變量值。
所以if __name__ == '__main__'的作用就很好理解了,即import時不執行下面的代碼,只有在直接執行這個文件時才運行之后的代碼。這算是一種約定俗成的寫法,如果不怕文件被import,可以不用這個。
專欄信息
專欄目錄:目錄
總結
以上是生活随笔為你收集整理的python模块讲解_python模块详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea spring tomcat启动
- 下一篇: 数组的合并和升序排列_leetcode