Python3 模塊

? 用 python 解釋器來(lái)編程從 Python 解釋器退出再進(jìn)入,那么你定義的所有的方法和變量就都消失了。

為此 Python 提供了一個(gè)辦法,把這些定義存放在文件中,為一些腳本或者交互式的解釋器實(shí)例使用,這個(gè)文件被稱為模塊。

模塊是一個(gè)包含所有你定義的函數(shù)和變量的文件,其后綴名是.py。模塊可以被別的程序引入,以使用該模塊中的函數(shù)等功能。這也是使用 python 標(biāo)準(zhǔn)庫(kù)的方法。

下面是一個(gè)使用 python 標(biāo)準(zhǔn)庫(kù)中模塊的例子。

#!/usr/bin/python3# 文件名: using_sys.pyimportsysprint('命令行參數(shù)如下:')foriinsys.argv:print(i)print('\n\nPython 路徑為:',sys.path,'\n')

執(zhí)行結(jié)果如下所示:

$ python using_sys.py參數(shù)1參數(shù)2命令行參數(shù)如下:using_sys.py參數(shù)1參數(shù)2Python路徑為:['/root','/usr/lib/python3.4','/usr/lib/python3.4/plat-x86_64-linux-gnu','/usr/lib/python3.4/lib-dynload','/usr/local/lib/python3.4/dist-packages','/usr/lib/python3/dist-packages']

1、import sys 引入 python 標(biāo)準(zhǔn)庫(kù)中的 sys.py 模塊;這是引入某一模塊的方法。

2、sys.argv 是一個(gè)包含命令行參數(shù)的列表。

3、sys.path 包含了一個(gè) Python 解釋器自動(dòng)查找所需模塊的路徑的列表。

import 語(yǔ)句

想使用 Python 源文件,只需在另一個(gè)源文件里執(zhí)行 import 語(yǔ)句,語(yǔ)法如下:

importmodule1[,module2[,...moduleN]

當(dāng)解釋器遇到 import 語(yǔ)句,如果模塊在當(dāng)前的搜索路徑就會(huì)被導(dǎo)入。

搜索路徑是一個(gè)解釋器會(huì)先進(jìn)行搜索的所有目錄的列表。如想要導(dǎo)入模塊 support,需要把命令放在腳本的頂端:

support.py 文件代碼為:

#!/usr/bin/python3# Filename: support.pydefprint_func(par):print("Hello : ",par)return

test.py 引入 support 模塊:

#!/usr/bin/python3# Filename: test.py# 導(dǎo)入模塊importsupport# 現(xiàn)在可以調(diào)用模塊里包含的函數(shù)了support.print_func("Runoob")

以上實(shí)例輸出結(jié)果:

$ python3 test.pyHello:Runoob

一個(gè)模塊只會(huì)被導(dǎo)入一次,不管你執(zhí)行了多少次import。這樣可以防止導(dǎo)入模塊被一遍又一遍地執(zhí)行。

當(dāng)我們使用import語(yǔ)句的時(shí)候,Python解釋器是怎樣找到對(duì)應(yīng)的文件的呢?

這就涉及到Python的搜索路徑,搜索路徑是由一系列目錄名組成的,Python解釋器就依次從這些目錄中去尋找所引入的模塊。

這看起來(lái)很像環(huán)境變量,事實(shí)上,也可以通過(guò)定義環(huán)境變量的方式來(lái)確定搜索路徑。

搜索路徑是在Python編譯或安裝的時(shí)候確定的,安裝新的庫(kù)應(yīng)該也會(huì)修改。搜索路徑被存儲(chǔ)在sys模塊中的path變量,做一個(gè)簡(jiǎn)單的實(shí)驗(yàn),在交互式解釋器中,輸入以下代碼:

>>>importsys>>>sys.path['','/usr/lib/python3.4','/usr/lib/python3.4/plat-x86_64-linux-gnu','/usr/lib/python3.4/lib-dynload','/usr/local/lib/python3.4/dist-packages','/usr/lib/python3/dist-packages']>>>

sys.path 輸出是一個(gè)列表,其中第一項(xiàng)是空串'',代表當(dāng)前目錄(若是從一個(gè)腳本中打印出來(lái)的話,可以更清楚地看出是哪個(gè)目錄),亦即我們執(zhí)行python解釋器的目錄(對(duì)于腳本的話就是運(yùn)行的腳本所在的目錄)。

因此若像我一樣在當(dāng)前目錄下存在與要引入模塊同名的文件,就會(huì)把要引入的模塊屏蔽掉。

了解了搜索路徑的概念,就可以在腳本中修改sys.path來(lái)引入一些不在搜索路徑中的模塊。

現(xiàn)在,在解釋器的當(dāng)前目錄或者 sys.path 中的一個(gè)目錄里面來(lái)創(chuàng)建一個(gè)fibo.py的文件,代碼如下:

# 斐波那契(fibonacci)數(shù)列模塊deffib(n):# 定義到 n 的斐波那契數(shù)列a,b=0,1whileb

然后進(jìn)入Python解釋器,使用下面的命令導(dǎo)入這個(gè)模塊:

>>>importfibo

這樣做并沒(méi)有把直接定義在fibo中的函數(shù)名稱寫入到當(dāng)前符號(hào)表里,只是把模塊fibo的名字寫到了那里。

可以使用模塊名稱來(lái)訪問(wèn)函數(shù):

>>>fibo.fib(1000)1123581321345589144233377610987>>>fibo.fib2(100)[1,1,2,3,5,8,13,21,34,55,89]>>>fibo.__name__'fibo'

如果你打算經(jīng)常使用一個(gè)函數(shù),你可以把它賦給一個(gè)本地的名稱:

>>>fib=fibo.fib>>>fib(500)1123581321345589144233377

from…import 語(yǔ)句

Python的from語(yǔ)句讓你從模塊中導(dǎo)入一個(gè)指定的部分到當(dāng)前命名空間中,語(yǔ)法如下:

frommodnameimportname1[,name2[,...nameN]]

例如,要導(dǎo)入模塊 fibo 的 fib 函數(shù),使用如下語(yǔ)句:

>>>fromfiboimportfib,fib2>>>fib(500)1123581321345589144233377

這個(gè)聲明不會(huì)把整個(gè)fibo模塊導(dǎo)入到當(dāng)前的命名空間中,它只會(huì)將fibo里的fib函數(shù)引入進(jìn)來(lái)。

From…import* 語(yǔ)句

把一個(gè)模塊的所有內(nèi)容全都導(dǎo)入到當(dāng)前的命名空間也是可行的,只需使用如下聲明:

frommodnameimport*

這提供了一個(gè)簡(jiǎn)單的方法來(lái)導(dǎo)入一個(gè)模塊中的所有項(xiàng)目。然而這種聲明不該被過(guò)多地使用。

深入模塊

模塊除了方法定義,還可以包括可執(zhí)行的代碼。這些代碼一般用來(lái)初始化這個(gè)模塊。這些代碼只有在第一次被導(dǎo)入時(shí)才會(huì)被執(zhí)行。

每個(gè)模塊有各自獨(dú)立的符號(hào)表,在模塊內(nèi)部為所有的函數(shù)當(dāng)作全局符號(hào)表來(lái)使用。

所以,模塊的作者可以放心大膽的在模塊內(nèi)部使用這些全局變量,而不用擔(dān)心把其他用戶的全局變量搞花。

從另一個(gè)方面,當(dāng)你確實(shí)知道你在做什么的話,你也可以通過(guò) modname.itemname 這樣的表示法來(lái)訪問(wèn)模塊內(nèi)的函數(shù)。

模塊是可以導(dǎo)入其他模塊的。在一個(gè)模塊(或者腳本,或者其他地方)的最前面使用 import 來(lái)導(dǎo)入一個(gè)模塊,當(dāng)然這只是一個(gè)慣例,而不是強(qiáng)制的。被導(dǎo)入的模塊的名稱將被放入當(dāng)前操作的模塊的符號(hào)表中。

還有一種導(dǎo)入的方法,可以使用 import 直接把模塊內(nèi)(函數(shù),變量的)名稱導(dǎo)入到當(dāng)前操作模塊。比如:

>>>fromfiboimportfib,fib2>>>fib(500)1123581321345589144233377

這種導(dǎo)入的方法不會(huì)把被導(dǎo)入的模塊的名稱放在當(dāng)前的字符表中(所以在這個(gè)例子里面,fibo 這個(gè)名稱是沒(méi)有定義的)。

這還有一種方法,可以一次性的把模塊中的所有(函數(shù),變量)名稱都導(dǎo)入到當(dāng)前模塊的字符表:

>>>fromfiboimport*>>>fib(500)1123581321345589144233377

這將把所有的名字都導(dǎo)入進(jìn)來(lái),但是那些由單一下劃線(_)開(kāi)頭的名字不在此例。大多數(shù)情況, Python程序員不使用這種方法,因?yàn)橐氲钠渌鼇?lái)源的命名,很可能覆蓋了已有的定義。

__name__屬性

一個(gè)模塊被另一個(gè)程序第一次引入時(shí),其主程序?qū)⑦\(yùn)行。如果我們想在模塊被引入時(shí),模塊中的某一程序塊不執(zhí)行,我們可以用__name__屬性來(lái)使該程序塊僅在該模塊自身運(yùn)行時(shí)執(zhí)行。

#!/usr/bin/python3# Filename: using_name.pyif__name__=='__main__':print('程序自身在運(yùn)行')else:print('我來(lái)自另一模塊')

運(yùn)行輸出如下:

$ python using_name.py程序自身在運(yùn)行

$ python>>>importusing_name我來(lái)自另一模塊>>>

說(shuō)明:每個(gè)模塊都有一個(gè)__name__屬性,當(dāng)其值是'__main__'時(shí),表明該模塊自身在運(yùn)行,否則是被引入。

dir() 函數(shù)

內(nèi)置的函數(shù)dir()可以找到模塊內(nèi)定義的所有名稱。以一個(gè)字符串列表的形式返回:

>>>importfibo,sys>>>dir(fibo)['__name__','fib','fib2']>>>dir(sys)['__displayhook__','__doc__','__excepthook__','__loader__','__name__','__package__','__stderr__','__stdin__','__stdout__','_clear_type_cache','_current_frames','_debugmallocstats','_getframe','_home','_mercurial','_xoptions','abiflags','api_version','argv','base_exec_prefix','base_prefix','builtin_module_names','byteorder','call_tracing','callstats','copyright','displayhook','dont_write_bytecode','exc_info','excepthook','exec_prefix','executable','exit','flags','float_info','float_repr_style','getcheckinterval','getdefaultencoding','getdlopenflags','getfilesystemencoding','getobjects','getprofile','getrecursionlimit','getrefcount','getsizeof','getswitchinterval','gettotalrefcount','gettrace','hash_info','hexversion','implementation','int_info','intern','maxsize','maxunicode','meta_path','modules','path','path_hooks','path_importer_cache','platform','prefix','ps1','setcheckinterval','setdlopenflags','setprofile','setrecursionlimit','setswitchinterval','settrace','stderr','stdin','stdout','thread_info','version','version_info','warnoptions']

如果沒(méi)有給定參數(shù),那么 dir() 函數(shù)會(huì)羅列出當(dāng)前定義的所有名稱:

>>>a=[1,2,3,4,5]>>>importfibo>>>fib=fibo.fib>>>dir()# 得到一個(gè)當(dāng)前模塊中定義的屬性列表['__builtins__','__name__','a','fib','fibo','sys']>>>a=5# 建立一個(gè)新的變量 'a'>>>dir()['__builtins__','__doc__','__name__','a','sys']>>>>>>dela# 刪除變量名a>>>>>>dir()['__builtins__','__doc__','__name__','sys']>>>

標(biāo)準(zhǔn)模塊

Python 本身帶著一些標(biāo)準(zhǔn)的模塊庫(kù),在 Python 庫(kù)參考文檔中將會(huì)介紹到(就是后面的"庫(kù)參考文檔")。

有些模塊直接被構(gòu)建在解析器里,這些雖然不是一些語(yǔ)言內(nèi)置的功能,但是他卻能很高效的使用,甚至是系統(tǒng)級(jí)調(diào)用也沒(méi)問(wèn)題。

這些組件會(huì)根據(jù)不同的操作系統(tǒng)進(jìn)行不同形式的配置,比如 winreg 這個(gè)模塊就只會(huì)提供給 Windows 系統(tǒng)。

應(yīng)該注意到這有一個(gè)特別的模塊 sys ,它內(nèi)置在每一個(gè) Python 解析器中。變量 sys.ps1 和 sys.ps2 定義了主提示符和副提示符所對(duì)應(yīng)的字符串:

>>>importsys>>>sys.ps1'>>> '>>>sys.ps2'... '>>>sys.ps1='C> 'C>print('Yuck!')Yuck!C>

包是一種管理 Python 模塊命名空間的形式,采用"點(diǎn)模塊名稱"。

比如一個(gè)模塊的名稱是 A.B, 那么他表示一個(gè)包 A中的子模塊 B 。

就好像使用模塊的時(shí)候,你不用擔(dān)心不同模塊之間的全局變量相互影響一樣,采用點(diǎn)模塊名稱這種形式也不用擔(dān)心不同庫(kù)之間的模塊重名的情況。

這樣不同的作者都可以提供 NumPy 模塊,或者是 Python 圖形庫(kù)。

不妨假設(shè)你想設(shè)計(jì)一套統(tǒng)一處理聲音文件和數(shù)據(jù)的模塊(或者稱之為一個(gè)"包")。

現(xiàn)存很多種不同的音頻文件格式(基本上都是通過(guò)后綴名區(qū)分的,例如: .wav,:file:.aiff,:file:.au,),所以你需要有一組不斷增加的模塊,用來(lái)在不同的格式之間轉(zhuǎn)換。

并且針對(duì)這些音頻數(shù)據(jù),還有很多不同的操作(比如混音,添加回聲,增加均衡器功能,創(chuàng)建人造立體聲效果),所你還需要一組怎么也寫不完的模塊來(lái)處理這些操作。

這里給出了一種可能的包結(jié)構(gòu)(在分層的文件系統(tǒng)中):

sound/頂層包__init__.py初始化sound包formats/文件格式轉(zhuǎn)換子包__init__.py

wavread.py

wavwrite.py

aiffread.py

aiffwrite.py

auread.py

auwrite.py...effects/聲音效果子包__init__.py

echo.py

surround.py

reverse.py...filters/filters子包__init__.py

equalizer.py

vocoder.py

karaoke.py...

在導(dǎo)入一個(gè)包的時(shí)候,Python 會(huì)根據(jù) sys.path 中的目錄來(lái)尋找這個(gè)包中包含的子目錄。

目錄只有包含一個(gè)叫做 __init__.py 的文件才會(huì)被認(rèn)作是一個(gè)包,主要是為了避免一些濫俗的名字(比如叫做 string)不小心的影響搜索路徑中的有效模塊。

最簡(jiǎn)單的情況,放一個(gè)空的 :file:__init__.py就可以了。當(dāng)然這個(gè)文件中也可以包含一些初始化代碼或者為(將在后面介紹的) __all__變量賦值。

用戶可以每次只導(dǎo)入一個(gè)包里面的特定模塊,比如:

importsound.effects.echo

這將會(huì)導(dǎo)入子模塊:sound.effects.echo。 他必須使用全名去訪問(wèn):

sound.effects.echo.echofilter(input,output,delay=0.7,atten=4)

還有一種導(dǎo)入子模塊的方法是:

fromsound.effectsimportecho

這同樣會(huì)導(dǎo)入子模塊: echo,并且他不需要那些冗長(zhǎng)的前綴,所以他可以這樣使用:

echo.echofilter(input,output,delay=0.7,atten=4)

還有一種變化就是直接導(dǎo)入一個(gè)函數(shù)或者變量:

fromsound.effects.echoimportechofilter

同樣的,這種方法會(huì)導(dǎo)入子模塊: echo,并且可以直接使用他的 echofilter() 函數(shù):

echofilter(input, output, delay=0.7, atten=4)

注意當(dāng)使用from package import item這種形式的時(shí)候,對(duì)應(yīng)的item既可以是包里面的子模塊(子包),或者包里面定義的其他名稱,比如函數(shù),類或者變量。

import語(yǔ)法會(huì)首先把item當(dāng)作一個(gè)包定義的名稱,如果沒(méi)找到,再試圖按照一個(gè)模塊去導(dǎo)入。如果還沒(méi)找到,恭喜,一個(gè):exc:ImportError 異常被拋出了。

反之,如果使用形如import item.subitem.subsubitem這種導(dǎo)入形式,除了最后一項(xiàng),都必須是包,而最后一項(xiàng)則可以是模塊或者是包,但是不可以是類,函數(shù)或者變量的名字。

從一個(gè)包中導(dǎo)入*

設(shè)想一下,如果我們使用 from sound.effects import *會(huì)發(fā)生什么?

Python 會(huì)進(jìn)入文件系統(tǒng),找到這個(gè)包里面所有的子模塊,一個(gè)一個(gè)的把它們都導(dǎo)入進(jìn)來(lái)。

但是很不幸,這個(gè)方法在 Windows平臺(tái)上工作的就不是非常好,因?yàn)閃indows是一個(gè)大小寫不區(qū)分的系統(tǒng)。

在這類平臺(tái)上,沒(méi)有人敢擔(dān)保一個(gè)叫做 ECHO.py 的文件導(dǎo)入為模塊 echo 還是 Echo 甚至 ECHO。

(例如,Windows 95就很討厭的把每一個(gè)文件的首字母大寫顯示)而且 DOS 的 8+3 命名規(guī)則對(duì)長(zhǎng)模塊名稱的處理會(huì)把問(wèn)題搞得更糾結(jié)。

為了解決這個(gè)問(wèn)題,只能煩勞包作者提供一個(gè)精確的包的索引了。

導(dǎo)入語(yǔ)句遵循如下規(guī)則:如果包定義文件 __init__.py 存在一個(gè)叫做 __all__ 的列表變量,那么在使用 from package import * 的時(shí)候就把這個(gè)列表中的所有名字作為包內(nèi)容導(dǎo)入。

作為包的作者,可別忘了在更新包之后保證 __all__ 也更新了啊。你說(shuō)我就不這么做,我就不使用導(dǎo)入*這種用法,好吧,沒(méi)問(wèn)題,誰(shuí)讓你是老板呢。這里有一個(gè)例子,在:file:sounds/effects/__init__.py中包含如下代碼:

__all__=["echo","surround","reverse"]

這表示當(dāng)你使用from sound.effects import *這種用法時(shí),你只會(huì)導(dǎo)入包里面這三個(gè)子模塊。

如果__all__真的沒(méi)有定義,那么使用from sound.effects import *這種語(yǔ)法的時(shí)候,就不會(huì)導(dǎo)入包 sound.effects 里的任何子模塊。他只是把包sound.effects和它里面定義的所有內(nèi)容導(dǎo)入進(jìn)來(lái)(可能運(yùn)行__init__.py里定義的初始化代碼)。

這會(huì)把 __init__.py 里面定義的所有名字導(dǎo)入進(jìn)來(lái)。并且他不會(huì)破壞掉我們?cè)谶@句話之前導(dǎo)入的所有明確指定的模塊。看下這部分代碼:

importsound.effects.echoimportsound.effects.surroundfromsound.effectsimport*

這個(gè)例子中,在執(zhí)行from...import前,包sound.effects中的echo和surround模塊都被導(dǎo)入到當(dāng)前的命名空間中了。(當(dāng)然如果定義了__all__就更沒(méi)問(wèn)題了)

通常我們并不主張使用*這種方法來(lái)導(dǎo)入模塊,因?yàn)檫@種方法經(jīng)常會(huì)導(dǎo)致代碼的可讀性降低。不過(guò)這樣倒的確是可以省去不少敲鍵的功夫,而且一些模塊都設(shè)計(jì)成了只能通過(guò)特定的方法導(dǎo)入。

記住,使用from Package import specific_submodule這種方法永遠(yuǎn)不會(huì)有錯(cuò)。事實(shí)上,這也是推薦的方法。除非是你要導(dǎo)入的子模塊有可能和其他包的子模塊重名。

如果在結(jié)構(gòu)中包是一個(gè)子包(比如這個(gè)例子中對(duì)于包sound來(lái)說(shuō)),而你又想導(dǎo)入兄弟包(同級(jí)別的包)你就得使用導(dǎo)入絕對(duì)的路徑來(lái)導(dǎo)入。比如,如果模塊sound.filters.vocoder 要使用包sound.effects中的模塊echo,你就要寫成 from sound.effects import echo。

from.importechofrom..importformatsfrom..filtersimportequalizer

無(wú)論是隱式的還是顯式的相對(duì)導(dǎo)入都是從當(dāng)前模塊開(kāi)始的。主模塊的名字永遠(yuǎn)是"__main__",一個(gè)Python應(yīng)用程序的主模塊,應(yīng)當(dāng)總是使用絕對(duì)路徑引用。

包還提供一個(gè)額外的屬性__path__。這是一個(gè)目錄列表,里面每一個(gè)包含的目錄都有為這個(gè)包服務(wù)的__init__.py,你得在其他__init__.py被執(zhí)行前定義哦。可以修改這個(gè)變量,用來(lái)影響包含在包里面的模塊和子包。

這個(gè)功能并不常用,一般用來(lái)擴(kuò)展包里面的模塊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Python3 模塊學(xué)習(xí) 基本概念 為了編寫可維護(hù)的代碼,我們把很多函數(shù)分組,分別放到不同的文件里,這樣,每個(gè)文件...
    weir_will閱讀 586評(píng)論 0 2
  • 7.1讓你的模塊可用 將模塊放置在正確的位置,可用下面的函數(shù)查看“正確的位置” 注意:將自己的包/模塊 放入到這些...
    閃電俠悟空閱讀 1,442評(píng)論 0 0
  • 1. 簡(jiǎn)介 模塊是一個(gè)包含所有自定義的函數(shù)和變量的文件,其后綴名是.py 模塊可以被別的程序引入以使用該模塊中的函...
    Mr_ox閱讀 322評(píng)論 0 0
  • 模塊 實(shí)質(zhì)就是py文件。查看本地系統(tǒng)自帶的模塊 如果想安裝其他模塊,可以通過(guò) 如果是python3 如果ubunt...
    jose_dl閱讀 242評(píng)論 0 0
  • 9歲那年,她穿著姥爺撿來(lái)的一雙拖鞋摔倒在堅(jiān)硬又臟兮兮的地上,細(xì)小的砂礫嵌在右膝里,血絲一層一層的漫了出來(lái),她...
    由零開(kāi)始r閱讀 334評(píng)論 0 0