每天一小时python官方文档学习(七)————模块与包
6. 模塊
模塊是一個(gè)包含Python定義和語(yǔ)句的文件,實(shí)際上就是一個(gè)正常的.py文件。但是作用和普通需要運(yùn)行的程序不一樣,它實(shí)際上有點(diǎn)像函數(shù)。如果說(shuō)函數(shù)實(shí)現(xiàn)了代碼的重用,模塊則是實(shí)現(xiàn)了函數(shù)的重用。我們?nèi)绻朐诓煌某绦蛑惺褂猛粋€(gè)函數(shù), 不必把這個(gè)函數(shù)復(fù)制到每一個(gè)程序中去,而是通過(guò)把函數(shù)寫在一個(gè)模塊中,然后程序通過(guò)導(dǎo)入模塊就可以使用這個(gè)函數(shù)了。
模塊文件名就是模塊名后跟文件后綴 .py 。在一個(gè)模塊內(nèi)部,模塊名(作為一個(gè)字符串)可以通過(guò)全局變量 __name__ 的值獲得。例如,你可以在當(dāng)前目錄下創(chuàng)建一個(gè)名為 fibo.py 的文件,模塊名即為fibo,而文件中含有以下內(nèi)容:
# 斐波拉契數(shù)列模塊def fib(n): # 打印斐波拉契數(shù)列a, b = 0, 1while a < n:print(a, end=' ')a, b = b, a+bprint()def fib2(n): # 返回斐波拉契數(shù)列的列表result = []a, b = 0, 1while a < n:result.append(a)a, b = b, a+breturn result這個(gè)fibo.py文件就是所謂的模塊文件,它里面就是兩個(gè)函數(shù),一個(gè)負(fù)責(zé)打印斐波拉契數(shù)列,另一個(gè)負(fù)責(zé)返回斐波拉契數(shù)列的列表。我們通過(guò)在Python解釋器中輸入import指令即可導(dǎo)入這個(gè)模塊:
>>> import fibo在當(dāng)前的符號(hào)表中,這并不會(huì)直接進(jìn)入到定義在 fibo 函數(shù)內(nèi)的名稱;它只是進(jìn)入到模塊名 fibo 中。你可以用模塊名訪問(wèn)這些函數(shù):
>>> fibo.fib(1000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>> fibo.fib2(100) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> fibo.__name__ #查看全局變量__name__,即顯示模塊名 'fibo'除了直接訪問(wèn)和調(diào)用,把模塊中函數(shù)賦值給一個(gè)局部變量也是可以的:
>>> fib = fibo.fib >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 3776.1. 有關(guān)模塊的更多信息
我們都知道,模塊可以包含可執(zhí)行的語(yǔ)句以及函數(shù)定義。這些語(yǔ)句通常是用于初始化模塊的,它們僅在模塊第一次在 import 語(yǔ)句中被導(dǎo)入時(shí)才執(zhí)行(實(shí)際上,函數(shù)定義也是“被執(zhí)行”的“語(yǔ)句”,模塊級(jí)函數(shù)定義的執(zhí)行在模塊的全局符號(hào)表中輸入該函數(shù)名)。
每個(gè)模塊都有它自己的私有符號(hào)表,該表用作模塊中定義的所有函數(shù)的全局符號(hào)表。因此,模塊的作者可以在模塊內(nèi)使用全局變量,而不必?fù)?dān)心與用戶的全局變量發(fā)生意外沖突。
import 語(yǔ)句有一個(gè)變體,它可以把名字從(from)一個(gè)被調(diào)模塊內(nèi)直接導(dǎo)入(import)到現(xiàn)模塊的符號(hào)表里。例如:
>>> from fibo import fib >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377這并不會(huì)把被調(diào)模塊名引入到局部變量表里,因此在這個(gè)例子里,fibo 是未被定義的,fibo里面只有fib被導(dǎo)入了,fib2未被導(dǎo)入。如果想導(dǎo)入模塊內(nèi)定義的所有名稱:
>>> from fibo import * >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377這會(huì)調(diào)入所有不以下劃線_開頭的名稱。 在多數(shù)情況下,Python程序員都不會(huì)使用這個(gè)功能,因?yàn)樗诮忉屍髦幸肓艘唤M未知的名稱,而它們很可能會(huì)覆蓋一些你已經(jīng)定義過(guò)的東西。注意通常情況下從一個(gè)模塊或者包內(nèi)調(diào)入 * 的做法是不太被接受的, 因?yàn)檫@通常會(huì)導(dǎo)致代碼的可讀性很差。不過(guò),在交互式編譯器中為了節(jié)省打字可以這么用。
最后,我們可以在模塊名稱后面加上 as,則跟在 as 之后的名稱將直接綁定到所導(dǎo)入的模塊,這通常用于給模塊名提供一個(gè)縮寫,則調(diào)用模塊函數(shù)時(shí)不用寫那么多字,例如import tensorflow as tf、import numpy as np等等。
6.1.1. 以腳本的方式執(zhí)行模塊
模塊文件既然是.py文件,那當(dāng)然也可以直接執(zhí)行它,在Python解釋器中輸入:
>>> python fibo.py # 如果有參數(shù)則寫在這里模塊里的代碼會(huì)被執(zhí)行。那直接執(zhí)行和導(dǎo)入模塊有什么區(qū)別呢?
區(qū)別就在于 __name__ 的值會(huì)不一樣。上面我們看到,導(dǎo)入模塊后,通過(guò)fibo.__name__我們能看到__name__的值為’fibo’即模塊名;但是直接執(zhí)行以后,__name__會(huì)被賦值為 "__main__"。 因此,我們可以通過(guò)條件判斷語(yǔ)句,規(guī)定一些語(yǔ)句時(shí)只有直接執(zhí)行模塊時(shí)才有效的:
if __name__ == "__main__":# 直接執(zhí)行模塊時(shí)才會(huì)運(yùn)行的語(yǔ)句,導(dǎo)入模塊時(shí)不運(yùn)行6.1.2. 模塊搜索路徑
當(dāng)一個(gè)模塊被導(dǎo)入時(shí),解釋器會(huì)怎么樣在電腦中尋找這個(gè)模塊文件呢?
解釋器首先尋找具有該名稱的內(nèi)置模塊。如果沒(méi)有找到,然后解釋器從 sys.path 變量給出的目錄列表里尋找文件。sys.path 初始有這些目錄地址:
- 包含輸入腳本的目錄(或者未指定文件時(shí)的當(dāng)前目錄)
- PYTHONPATH (一個(gè)包含目錄名稱的列表,它和shell變量 PATH有一樣的語(yǔ)法)
- 取決于安裝的默認(rèn)設(shè)置
6.1.3. “編譯過(guò)的”Python文件
為了加速模塊載入,Python在 __pycache__ 目錄里緩存了每個(gè)模塊的編譯后版本,名稱為 module.version.pyc ,其中名稱中的版本字段對(duì)編譯文件的格式進(jìn)行編碼,它一般使用Python版本號(hào)。
6.2. 標(biāo)準(zhǔn)模塊
Python附帶了一個(gè)標(biāo)準(zhǔn)模塊庫(kù),這些模塊內(nèi)置于解釋器中,它們提供對(duì)不屬于語(yǔ)言核心但仍然內(nèi)置的操作的訪問(wèn),以提高效率或提供對(duì)系統(tǒng)調(diào)用等操作系統(tǒng)原語(yǔ)的訪問(wèn)。標(biāo)準(zhǔn)庫(kù)也是屬于不要求全部記住,但是常用的應(yīng)該有印象的知識(shí),建議多查閱官方文檔
這些模塊的集合是一個(gè)配置選項(xiàng),它也取決于底層平臺(tái)。例如,winreg 模塊只在Windows操作系統(tǒng)上提供。一個(gè)特別值得注意的模塊 sys,它被內(nèi)嵌到每一個(gè)Python解釋器中。變量 sys.ps1 和 sys.ps2 定義用作主要和輔助提示的字符串,這兩個(gè)變量只有在編譯器是交互模式下才被定義,例如:
>>> import sys >>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print('Yuck!') Yuck! C>6.3. dir() 函數(shù)
內(nèi)置函數(shù) dir() 用于查找模塊定義的名稱,它返回一個(gè)排序過(guò)的字符串列表,這個(gè)列表就包括所有類型的名稱:變量,模塊,函數(shù),等等:
>>> import fibo, sys # 先導(dǎo)入fibo和sys模塊 >>> dir(fibo) # 查找fibo模塊 ['__name__', 'fib', 'fib2'] >>> dir(sys) # 查找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() 會(huì)列出你當(dāng)前定義的名稱:
>>> a = [1, 2, 3, 4, 5] >>> import fibo >>> fib = fibo.fib >>> dir() ['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']dir() 不會(huì)列出內(nèi)置函數(shù)和變量的名稱,如果你想要這些,它們的定義是在標(biāo)準(zhǔn)模塊 builtins 中。
6.4. 包
包是一種通過(guò)用“帶點(diǎn)號(hào)的模塊名”來(lái)構(gòu)造 Python 模塊命名空間的方法,簡(jiǎn)單來(lái)說(shuō),包就是模塊的集合。例如,模塊名 A.B 表示 A 包中名為 B 的子模塊。正如模塊的使用使得不同模塊的作者不必?fù)?dān)心彼此的全局變量名稱一樣,使用加點(diǎn)的模塊名可以使得 NumPy 或 Pillow 等多模塊軟件包的作者不必?fù)?dān)心彼此的模塊名稱一樣。
假設(shè)有這么一個(gè)包的文件,它有三個(gè)子包,每個(gè)子包里面有各自的模塊:
sound/ 包含三個(gè)子包的包__init__.py 對(duì)sound初始化的模塊formats/ 用于文件格式轉(zhuǎn)換的子包__init__.py 對(duì)formats初始化的模塊wavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py...effects/ 包含不同音效的子包__init__.py 對(duì)effects初始化的模塊echo.pysurround.pyreverse.py...filters/ 用于聲音濾波的子包__init__.py 對(duì)filters初始化的模塊equalizer.pyvocoder.pykaraoke.py...我們可以從包中導(dǎo)入單個(gè)模塊,例如:
import sound.effects.echo這會(huì)加載子模塊 sound.effects.echo ,但引用它時(shí)必須使用它的全名:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)也可以直接導(dǎo)入子模塊:
from sound.effects import echo這會(huì)加載子模塊 echo ,并使其在沒(méi)有包前綴的情況下可用,因此可以不使用全名:
echo.echofilter(input, output, delay=0.7, atten=4)甚至還可以直接導(dǎo)入所需的函數(shù)或變量:
from sound.effects.echo import echofilter同樣,這也會(huì)加載子模塊 echo,但這會(huì)使其函數(shù) echofilter() 直接可用:
echofilter(input, output, delay=0.7, atten=4)總結(jié)
以上是生活随笔為你收集整理的每天一小时python官方文档学习(七)————模块与包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 每天一小时python官方文档学习(六)
- 下一篇: 二叉树N叉数的前中后序遍历总结,pyth