Python引用模塊和查找模塊路徑
模塊間相互獨(dú)立相互引用是任何一種編程語言的基礎(chǔ)能力。對(duì)于“模塊”這個(gè)詞在各種編程語言中或許是不同的,但我們可以簡(jiǎn)單認(rèn)為一個(gè)程序文件是一個(gè)模塊,文件里包含了類或者方法的定義。對(duì)于編譯型的語言,比如C#中的一個(gè).cs文件,Java中的一個(gè).java或者編譯后的.class文件可以認(rèn)為是一個(gè)模塊(但常常不表述為模塊);對(duì)于解釋型的語言會(huì)更加直觀些,比如PHP的.php文件,在Python中就是.py文件可以認(rèn)為是一個(gè)模塊。在“模塊”之上有“包”,主要是為了方便組織和管理模塊。比如C#中編譯后的.dll文件(但常常不表述為包Package,而是庫Library),Java將.class打包后的.jar文件,PHP的.phar文件(模仿Java包),在Python中一個(gè)特殊定義的文件夾是一個(gè)包,可以打包為egg文件。但對(duì)于解釋型語言“包”并沒有編譯成低級(jí)語言而后打包的意思,只是更加方便模塊化和管理模塊間的依賴。每種編程語言對(duì)于模塊和包管理都有一定的約定,不了解這些約定,那會(huì)給學(xué)習(xí)這種語言的帶來障礙。下面我想來梳理一下Python的這些約定。
一、Python查找模塊的路徑
運(yùn)行Python應(yīng)用或引用Python模塊,Python解釋器要有一個(gè)查找的過程??梢酝ㄟ^設(shè)置一個(gè)環(huán)境變量PYTHONPATH為Python增加一個(gè)搜索路徑,以方便查找到相關(guān)Python模塊(不同的操作系統(tǒng)環(huán)境變量的設(shè)置稍有不同,默認(rèn)以下都是WIndows環(huán)境),這與眾多應(yīng)用程序需要設(shè)置一個(gè)系統(tǒng)環(huán)境變量的道理是一樣的。在命令行中可以通過以下命令設(shè)置:
C:\Users\Administrator>set PYTHONPATH=E:/Project/Python/ModuleAndPackage/
進(jìn)入Python環(huán)境后可以,通過Python的sys.path屬性獲得當(dāng)前搜索路徑的配置,可以看到之前我們?cè)O(shè)置的路徑已經(jīng)在當(dāng)前搜索路徑中了。
C:\Users\Administrator>python Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.path ['', 'E:\\Project\\Python\\ModuleAndPackage', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python\\DLLs', 'C:\\Python\\lib', 'C:\\Python\\lib\\plat-win', 'C:\\Python\\lib\\lib-tk', 'C:\\Python', 'C:\\Python\\lib\\site-packages'] >>>
也可以通過sys模塊的append方法在Python環(huán)境中增加搜索路徑。
>>> sys.path.append("E:\\Project\\Python\\ModuleAndPackage2") >>> sys.path ['', 'E:\\Project\\Python\\ModuleAndPackage', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python\\DLLs', 'C:\\Python\\lib', 'C:\\Python\\lib\\plat-win', 'C:\\Python\\lib\\lib-tk', 'C:\\Python', 'C:\\Python\\lib\\site-packages', 'E:\\Project\\Python\\ModuleAndPackage2'] >>>
二、Python中的模塊和包
前面已經(jīng)提到每個(gè).py文件都是可以認(rèn)為是一個(gè)Python模塊,.py文件中可以包含類、方法、變量和常量(Python還沒有嚴(yán)格意義上的常量,只是約定大寫的變量作為常量),文件內(nèi)也可以直接寫所有的邏輯語句并在加載時(shí)從上之下直接執(zhí)行,這與其他解釋型語言是類似的。例如我們選擇在文件夾ModuleAndPackage中創(chuàng)建一個(gè)文本文件person.py文件即創(chuàng)建了一個(gè)簡(jiǎn)單的Python模塊,其內(nèi)容如下:
# -*- coding: utf-8 -*- ID = 1 name = "This person" print namedef say(something): print name,'says', something
那么接下來我們就可以在Python環(huán)境中執(zhí)行person.py。我們可以直接像執(zhí)行一個(gè)批處理文件那樣執(zhí)行person.py,在cmd命令行輸入:
Python E:/Project/Python/ModuleAndPackage/person.py
本質(zhì)上任何一個(gè)Python應(yīng)用的入口模塊都是這樣被執(zhí)行的(像C#和Java中的main函數(shù)),但是引用一個(gè)模塊,就要建立運(yùn)行它的上下文環(huán)境。我們先設(shè)置一個(gè)環(huán)境變量PYTHONPATH,以便Python解釋器找到person.py模塊,然后import person模塊,即可訪問其中的方法或變量。
C:\Users\Administrator>python Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit ( Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import person This person>>> person.say("hello") This person says hello >>> print person.nameThis person>>>
Python需要去某些固定的路徑下去查找Python模塊,上面我們?cè)O(shè)置在ModuleAndPackage中查找。但是這些路徑下也是有目錄層次的,Python是如何查找子目錄中的模塊呢?特別是引用第三方包時(shí),我們也需要知道一定的層次關(guān)系。實(shí)際上,Python通過目錄和文件構(gòu)建包結(jié)構(gòu),并且包是層層嵌套的,和目錄層層嵌套是一樣的,這樣就構(gòu)成了包內(nèi)的訪問路徑(或者命名空間,也可以說Python應(yīng)用的命名空間與其目錄和文件結(jié)構(gòu)是對(duì)應(yīng)了,似乎缺少了一些靈活,但也更簡(jiǎn)單)。例如我們?cè)贛oduleAndPackage文件夾下,創(chuàng)建一個(gè)文件夾animal,里面創(chuàng)建一個(gè)文本文件pet.py,其內(nèi)容如下:
# -*- coding: utf-8 -*- ID = 2 name = "This pet" print namedef run(somewhere): print name,'runs', somewhere
那么如何引用pet.py這個(gè)模塊呢?按照Python的約定,需要在animal文件夾中創(chuàng)建名為__init__.py的空文本文件,以標(biāo)識(shí)animal文件夾是一個(gè)包。倘若animal文件夾內(nèi)還有文件夾作為包,也必須包含__init__.py文件。這樣就層層標(biāo)識(shí)了訪問的路徑。
>>> import animal.pet This pet>>> print animal.pet.name This pet>>> animal.pet.run("everywhere")This pet runs everywhere>>>
或者使用from關(guān)鍵字直接導(dǎo)入模塊內(nèi)的屬性或方法:
>>> from animal.pet import name,run >>> print name This pet>>> run("everywhere") This pet runs everywhere >>>
三、Python模塊間引用
簡(jiǎn)答來說,只要Python模塊在其執(zhí)行環(huán)境配置的搜索路徑中,并且其所在位置是包結(jié)構(gòu)的一部分,那么我們就可以引用該模塊。上文已經(jīng)提供了模塊引用的基本示例。只不過模塊間引用時(shí)import語句是寫在模塊文件中,我們修改person.py模塊的代碼。
1、from、import和as
# -*- coding: utf-8 -*- ID = 1 name = "This person" print name def say(something): print name,'says', something from animal.pet import name as pet_name, run as pet_run def have(): print name,'has', pet_name
import語句可以寫在文檔中的任何位置,甚至if語句中,以便更好的控制模塊引用。還可以通過as語句,使用另一個(gè)變量名進(jìn)行引用,以避免變量名沖突。
>>> import person This person This pet >>> print person.name This person >>> print person.pet_name This pet >>> person.have() This person has This pet >>>
2、*通配符
上面的import代碼明確了引用的變量名,但如果想引用模塊中所有變量可以使用*通配符,將上面的import語句改寫如下:
from animal.pet import *
但這樣有可能造成變量名沖突,如下name變量發(fā)生沖突,覆蓋了person自己的name變量的值:
>>> import person This person This pet >>> print person.name This pet
但如果想用*通配符,又不想引用模塊中的所有變量,可以在模塊中用變量__all__進(jìn)行限制,修改pet.py,限制只引用ID和run兩個(gè)變量名。
# -*- coding: utf-8 -*- __all__ = ['ID','run'] ID = 2 name = "This pet" print name def run(somewhere): print name,'runs', somewhere
因?yàn)闆]有引用pet模塊中的name變量,person的name變量值沒有改變,run卻可以調(diào)用了。
>>> import person This person This pet >>> print person.name This person >>> person.run("nowhere") This pet runs nowhere >>>
3、引用包
上面都是引用具體的animal.pet模塊,但是這對(duì)于一個(gè)相對(duì)獨(dú)立且擁有眾多的模塊的包來說就顯得麻煩了,可以直接import animal嗎?答案是肯定的,但是Python不像C#引用dll或者java引用jar那樣,引用后包內(nèi)的模塊就可以通過命名空間直接訪問了(在訪問控制許可下)。默認(rèn)情況下Python還是需要導(dǎo)入包內(nèi)的具體模塊的,但有個(gè)變通的辦法,就是使用包中__init__.py文件,提前準(zhǔn)備包內(nèi)需要被引用的各個(gè)模塊中的變量,類似于向外部引用者暴露包內(nèi)接口。__init__.py文件代碼是在包或者包內(nèi)模塊被引用時(shí)執(zhí)行的,因而可以在其中做一些初始化的工作。修改animal文件夾中__init__.py文件如下,其中模塊可以使用絕對(duì)路徑和相對(duì)路徑,相對(duì)路徑中一個(gè)句點(diǎn).代表同級(jí)目錄,兩個(gè)句點(diǎn)..代表父目錄。
print "__init__" from pet import name as pet_name, run as pet_run#from animal.pet import name as pet_name, run as pet_run #from .pet import name as pet_name, run as pet_run
修改person.py,直接引用anmial包:
# -*- coding: utf-8 -*- ID = 1 name = "This person" print name def say(something): print name,'says', something import animal def have(): print name,'has', pet_name
在Python環(huán)境中引用person模塊,person引用animal,并自動(dòng)執(zhí)行__init__的代碼加載相關(guān)變量,通過dir方法可以查看模塊中的變量,其中兩個(gè)下劃線開始的變量每個(gè)模塊都有,這些變量具有特殊的作用,是Python預(yù)定義的。
>>> import person This person __init__ This pet >>> dir(person) ['ID', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'have', 'name', 'pet', 'pet_name', 'pet_run', 'say'] >>> print person.pet_name This pet >>> person.pet_run("nowhere") This pet runs nowhere >>>
關(guān)于Python引用模塊和Python查找模塊路徑的相關(guān)知識(shí),小編就給大家介紹這么多,希望對(duì)大家有所幫助!
相關(guān)文章
python實(shí)現(xiàn)根據(jù)月份和日期得到星座的方法
這篇文章主要介紹了python實(shí)現(xiàn)根據(jù)月份和日期得到星座的方法,涉及Python操作字符串及數(shù)組的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03python判斷一個(gè)集合是否包含了另外一個(gè)集合中所有項(xiàng)的方法
這篇文章主要介紹了python判斷一個(gè)集合是否包含了另外一個(gè)集合中所有項(xiàng)的方法,涉及Python集合操作的相關(guān)技巧,需要的朋友可以參考下2015-06-06Python利用帶權(quán)重隨機(jī)數(shù)解決抽獎(jiǎng)和游戲爆裝備問題
帶權(quán)重隨機(jī)數(shù)即是隨機(jī)數(shù)各個(gè)區(qū)間段被抽中的概率根據(jù)權(quán)重而不同,這里我們就來看一下Python利用帶權(quán)重隨機(jī)數(shù)解決抽獎(jiǎng)和游戲爆裝備問題的方法,首先還是來進(jìn)一步解釋帶權(quán)隨機(jī)數(shù):2016-06-06caffe的python接口deploy生成caffemodel分類新的圖片
這篇文章主要為大家介紹了caffe的python接口生成deploy文件學(xué)習(xí)以及用訓(xùn)練好的模型(caffemodel)來分類新的圖片示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Python使用Pandas對(duì)csv文件進(jìn)行數(shù)據(jù)處理的方法
這篇文章主要介紹了Python使用Pandas對(duì)csv文件進(jìn)行數(shù)據(jù)處理的方法,本文通過實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08python3新特性函數(shù)注釋Function Annotations用法分析
這篇文章主要介紹了python3新特性函數(shù)注釋Function Annotations用法,結(jié)合實(shí)例形式分析了Python3函數(shù)注釋的定義方法與使用技巧,需要的朋友可以參考下2016-07-07Python遍歷pandas數(shù)據(jù)方法總結(jié)
本篇文章給大家詳細(xì)介紹了Python中遍歷pandas數(shù)據(jù)方法以及相關(guān)注意點(diǎn),對(duì)此有興趣的朋友參考學(xué)習(xí)下吧。2018-02-02Django model重寫save方法及update踩坑詳解
這篇文章主要介紹了Django model重寫save方法及update踩坑詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07python實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(精簡(jiǎn)版)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)的精簡(jiǎn)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11