更新時(shí)間:2018-09-07 來(lái)源:黑馬程序員人工智能+Python培訓(xùn)學(xué)院 瀏覽量:
模塊
如果你退出 Python 解釋器并重新進(jìn)入,你做的任何定義(變量和方法)都會(huì)丟失。因此,如果你想要編寫一些更大的程序,為準(zhǔn)備解釋器輸入使用一個(gè)文本編輯器會(huì)更好,并以那個(gè)文件替代作為輸入執(zhí)行。這就是傳說(shuō)中的 腳本。隨著你的程序變得越來(lái)越長(zhǎng),你可能想要將它分割成幾個(gè)更易于維護(hù)的文件。你也可能想在不同的程序中使用順手的函數(shù),而不是把代碼在它們之間中拷來(lái)拷去。
為了滿足這些需要,Python 提供了一個(gè)方法可以從文件中獲取定義,在腳本或者解釋器的一個(gè)交互式實(shí)例中使用。這樣的文件被稱為 模塊;模塊中的定義可以 導(dǎo)入 到另一個(gè)模塊或 主模塊 中(在腳本執(zhí)行時(shí)可以調(diào)用的變量集位于最高級(jí),并且處于計(jì)算器模式)。
模塊是包括 Python 定義和聲明的文件。文件名就是模塊名加上 .py 后綴。模塊的模塊名(做為一個(gè)字符串)可以由全局變量 *__name__ *得到。例如,你可以用自己慣用的文件編輯器在當(dāng)前目錄下創(chuàng)建一個(gè)叫 fibo.py 的文件,錄入如下內(nèi)容:
# Fibonacci numbers moduledef fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print(b, end=' ') a, b = b, a+b print()def fib2(n): # return Fibonacci series up to n result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
現(xiàn)在進(jìn)入 Python 解釋器并使用以下命令導(dǎo)入這個(gè)模塊:
>>> import fibo
1
這樣做不會(huì)直接把 fibo 中的函數(shù)導(dǎo)入當(dāng)前的語(yǔ)義表;它只是引入了模塊名 fibo。你可以通過(guò)模塊名按如下方式訪問(wèn)這個(gè)函數(shù):
>>> fibo.fib(1000)1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987>>> fibo.fib2(100)[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]>>> fibo.__name__'fibo'
1
2
3
4
5
6
如果打算頻繁使用一個(gè)函數(shù),你可以將它賦予一個(gè)本地變量:
>>> fib = fibo.fib>>> fib(500)1 1 2 3 5 8 13 21 34 55 89 144 233 377
1
2
3
1. 深入模塊
除了包含函數(shù)定義外,模塊也可以包含可執(zhí)行語(yǔ)句。這些語(yǔ)句一般用來(lái)初始化模塊。他們僅在 第一次 被導(dǎo)入的地方執(zhí)行一次。1
模塊可以導(dǎo)入其他的模塊。一個(gè)(好的)習(xí)慣是將所有的 import 語(yǔ)句放在模塊的開(kāi)始(或者是腳本),這并非強(qiáng)制。被導(dǎo)入的模塊名會(huì)放入當(dāng)前模塊的全局符號(hào)表中。
import 語(yǔ)句的一個(gè)變體直接從被導(dǎo)入的模塊中導(dǎo)入命名到本模塊的語(yǔ)義表中。例如:
>>> from fibo import fib, fib2>>> fib(500)1 1 2 3 5 8 13 21 34 55 89 144 233 377
1
2
3
這樣不會(huì)從局域語(yǔ)義表中導(dǎo)入模塊名(如上所示, fibo 沒(méi)有定義)。
甚至有種方式可以導(dǎo)入模塊中的所有定義:
>>> from fibo import *>>> fib(500)1 1 2 3 5 8 13 21 34 55 89 144 233 377
1
2
3
這樣可以導(dǎo)入所有除了以下劃線( _ )開(kāi)頭的命名。
需要注意的是在實(shí)踐中往往不鼓勵(lì)從一個(gè)模塊或包中使用 * 導(dǎo)入所有,因?yàn)檫@樣會(huì)讓代碼變得很難讀。不過(guò),在交互式會(huì)話中這樣用很方便省力。
出于性能考慮,每個(gè)模塊在每個(gè)解釋器會(huì)話中只導(dǎo)入一遍。因此,如果你修改了你的模塊,需要重啟解釋器;或者,如果你就是想交互式的測(cè)試這么一個(gè)模塊,可以用 imp.reload() 重新加載,例如 import imp; imp.reload(modulename)。
1
出于性能考慮,每個(gè)模塊在每個(gè)解釋器會(huì)話中只導(dǎo)入一遍。因此,如果你修改了你的模塊,需要重啟解釋器;或者,如果你就是想交互式的測(cè)試這么一個(gè)模塊,可以用 imp.reload() 重新加載,例如 import imp; imp.reload(modulename)。
1.1. 作為腳本來(lái)執(zhí)行模塊
當(dāng)你使用以下方式運(yùn)行 Python 模塊時(shí),模塊中的代碼便會(huì)被執(zhí)行:
python fibo.py <arguments>
1
模塊中的代碼會(huì)被執(zhí)行,就像導(dǎo)入它一樣,不過(guò)此時(shí)* __name__* 被設(shè)置為 “_main _ “。這相當(dāng)于,如果你在模塊后加入如下代碼:
if __name__ == "__main__": import sys fib(int(sys.argv[1]))
1
2
3
就可以讓此文件像作為模塊導(dǎo)入時(shí)一樣作為腳本執(zhí)行。此代碼只有在模塊作為 “main” 文件執(zhí)行時(shí)才被調(diào)用:
$ python fibo.py 501 1 2 3 5 8 13 21 34
1
2
如果模塊被導(dǎo)入,不會(huì)執(zhí)行這段代碼:
>>> import fibo>>>
1
2
這通常用來(lái)為模塊提供一個(gè)便于測(cè)試的用戶接口(將模塊作為腳本執(zhí)行測(cè)試需求)。
1.2. 模塊的搜索路徑
導(dǎo)入一個(gè)叫 spam 的模塊時(shí),解釋器先在當(dāng)前目錄中搜索名為 spam.py 的文件。如果沒(méi)有找到的話,接著會(huì)到 sys.path 變量中給出的目錄列表中查找。 sys.path 變量的初始值來(lái)自如下:
輸入腳本的目錄(當(dāng)前目錄)。 環(huán)境變量 PYTHONPATH 表示的目錄列表中搜索 (這和 shell 變量 PATH 具有一樣的語(yǔ)法,即一系列目錄名的列表)。 Python 默認(rèn)安裝路徑中搜索。 Note 在支持符號(hào)連接的文件系統(tǒng)中,輸入的腳本所在的目錄是符號(hào)連接指向的目錄。 換句話說(shuō)也就是包含符號(hào)鏈接的目錄不會(huì)被加到目錄搜索路徑中。
1
2
3
4
5
6
7
8
9
10
11
實(shí)際上,解釋器由 sys.path 變量指定的路徑目錄搜索模塊,該變量初始化時(shí)默認(rèn)包含了輸入腳本(或者當(dāng)前目錄), PYTHONPATH 和安裝目錄。這樣就允許 Python 程序了解如何修改或替換模塊搜索目錄。需要注意的是由于這些目錄中包含有搜索路徑中運(yùn)行的腳本,所以這些腳本不應(yīng)該和標(biāo)準(zhǔn)模塊重名,否則在導(dǎo)入模塊時(shí) Python 會(huì)嘗試把這些腳本當(dāng)作模塊來(lái)加載。這通常會(huì)引發(fā)錯(cuò)誤。請(qǐng)參見(jiàn) 標(biāo)準(zhǔn)模塊 以了解更多的信息。
1.3. “編譯的” Python 文件
為了加快加載模塊的速度,Python 會(huì)在_pycache_目錄下以 module.version.pyc 名字緩存每個(gè)模塊編譯后的版本,這里的版本編制了編譯后文件的格式。它通常會(huì)包含 Python 的版本號(hào)。例如,在 CPython 3.3 版中,spam.py 編譯后的版本將緩存為_(kāi)pycache_/spam.cpython-33.pyc。這種命名約定允許由不同發(fā)布和不同版本的 Python 編譯的模塊同時(shí)存在。
Python 會(huì)檢查源文件與編譯版的修改日期以確定它是否過(guò)期并需要重新編譯。這是完全自動(dòng)化的過(guò)程。同時(shí),編譯后的模塊是跨平臺(tái)的,所以同一個(gè)庫(kù)可以在不同架構(gòu)的系統(tǒng)之間共享。
Python 不檢查在兩個(gè)不同環(huán)境中的緩存。首先,它會(huì)永遠(yuǎn)重新編譯而且不會(huì)存儲(chǔ)直接從命令行加載的模塊。其次,如果沒(méi)有源模塊它不會(huì)檢查緩存。若要支持沒(méi)有源文件(只有編譯版)的發(fā)布,編譯后的模塊必須在源目錄下,并且必須沒(méi)有源文件的模塊。
部分高級(jí)技巧: 為了減少一個(gè)編譯模塊的大小,你可以在 Python 命令行中使用 -O 或者 -OO。-O 參數(shù)刪除了斷言語(yǔ)句,-OO 參數(shù)刪除了斷言語(yǔ)句和 __doc__ 字符串。 因?yàn)槟承┏绦蛞蕾囉谶@些變量的可用性,你應(yīng)該只在確定無(wú)誤的場(chǎng)合使用這一選項(xiàng)?!皟?yōu)化的” 模塊有一個(gè) .pyo 后綴而不是 .pyc 后綴。未來(lái)的版本可能會(huì)改變優(yōu)化的效果。 來(lái)自 .pyc 文件或 .pyo 文件中的程序不會(huì)比來(lái)自 .py 文件的運(yùn)行更快;.pyc 或 .pyo 文件只是在它們加載的時(shí)候更快一些。 compileall 模塊可以為指定目錄中的所有模塊創(chuàng)建 .pyc 文件(或者使用 -O 參數(shù)創(chuàng)建 .pyo 文件)。 在 PEP 3147 中有很多關(guān)這一部分內(nèi)容的細(xì)節(jié),并且包含了一個(gè)決策流程。
1
2
3
4
5
6
7
8
9
2. 標(biāo)準(zhǔn)模塊
Python 帶有一個(gè)標(biāo)準(zhǔn)模塊庫(kù),并發(fā)布有獨(dú)立的文檔,名為 Python 庫(kù)參考手冊(cè)(此后稱其為“庫(kù)參考手冊(cè)”)。有一些模塊內(nèi)置于解釋器之中,這些操作的訪問(wèn)接口不是語(yǔ)言內(nèi)核的一部分,但是已經(jīng)內(nèi)置于解釋器了。這既是為了提高效率,也是為了給系統(tǒng)調(diào)用等操作系統(tǒng)原生訪問(wèn)提供接口。這類模塊集合是一個(gè)依賴于底層平臺(tái)的配置選項(xiàng)。例如,winreg 模塊只提供在 Windows 系統(tǒng)上才有。有一個(gè)具體的模塊值得注意: sys ,這個(gè)模塊內(nèi)置于所有的 Python 解釋器。變量 sys.ps1 和 sys.ps2 定義了主提示符和輔助提示符字符串:
>>> import sys>>> sys.ps1'>>> '>>> sys.ps2'... '>>> sys.ps1 = 'C> 'C> print('Yuck!')Yuck!C>
1
2
3
4
5
6
7
8
9
這兩個(gè)變量只在解釋器的交互模式下有意義。
變量 sys.path 是解釋器模塊搜索路徑的字符串列表。它由環(huán)境變量 PYTHONPATH 初始化,如果沒(méi)有設(shè)定 PYTHONPATH ,就由內(nèi)置的默認(rèn)值初始化。你可以用標(biāo)準(zhǔn)的字符串操作修改它:
>>> import sys>>> sys.path.append('/ufs/guido/lib/python')
1
2
·
內(nèi)置函數(shù) dir() 用于按模塊名搜索模塊定義,它返回一個(gè)字符串類型的存儲(chǔ)列表:
>>> import fibo, 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']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
無(wú)參數(shù)調(diào)用時(shí),dir() 函數(shù)返回當(dāng)前定義的命名:
>>> a = [1, 2, 3, 4, 5]>>> import fibo>>> fib = fibo.fib>>> dir()['__builtins__', '__doc__', '__file__', '__name__', 'a', 'fib', 'fibo', 'sys']
1
2
3
4
5
注意該列表列出了所有類型的名稱:變量,模塊,函數(shù),等等。
dir() 不會(huì)列出內(nèi)置函數(shù)和變量名。如果你想列出這些內(nèi)容,它們?cè)跇?biāo)準(zhǔn)模塊 builtins 中定義:
>>> import builtins>>> dir(builtins) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
4. 包
包通常是使用用“圓點(diǎn)模塊名”的結(jié)構(gòu)化模塊命名空間。例如,名為 A.B 的模塊表示了名為 A 的包中名為 B 的子模塊。正如同用模塊來(lái)保存不同的模塊架構(gòu)可以避免全局變量之間的相互沖突,使用圓點(diǎn)模塊名保存像 NumPy 或 Python Imaging Library 之類的不同類庫(kù)架構(gòu)可以避免模塊之間的命名沖突。
假設(shè)你現(xiàn)在想要設(shè)計(jì)一個(gè)模塊集(一個(gè)“包”)來(lái)統(tǒng)一處理聲音文件和聲音數(shù)據(jù)。存在幾種不同的聲音格式(通常由它們的擴(kuò)展名來(lái)標(biāo)識(shí),例如:.wav, .aiff,.au ),于是,為了在不同類型的文件格式之間轉(zhuǎn)換,你需要維護(hù)一個(gè)不斷增長(zhǎng)的包集合??赡苣氵€想要對(duì)聲音數(shù)據(jù)做很多不同的操作(例如混音,添加回聲,應(yīng)用平衡 功能,創(chuàng)建一個(gè)人造效果),所以你要加入一個(gè)無(wú)限流模塊來(lái)執(zhí)行這些操作。你的包可能會(huì)是這個(gè)樣子(通過(guò)分級(jí)的文件體系來(lái)進(jìn)行分組):
sound/ Top-level package __init__.py Initialize the sound package formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py ... filters/ Subpackage for filters __init__.py equalizer.py vocoder.py karaoke.py ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
當(dāng)導(dǎo)入這個(gè)包時(shí),Python 通過(guò) sys.path 搜索路徑查找包含這個(gè)包的子目錄。
為了讓 Python 將目錄當(dāng)做內(nèi)容包,目錄中必須包含 init.py 文件。這是為了避免一個(gè)含有爛俗名字的目錄無(wú)意中隱藏了稍后在模塊搜索路徑中出現(xiàn)的有效模塊,比如 string。最簡(jiǎn)單的情況下,只需要一個(gè)空的 init.py 文件即可。當(dāng)然它也可以執(zhí)行包的初始化代碼,或者定義稍后介紹的 all 變量。
用戶可以每次只導(dǎo)入包里的特定模塊,例如:
import sound.effects.echo
1
這樣就導(dǎo)入了 sound.effects.echo 子模塊。它必需通過(guò)完整的名稱來(lái)引用:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
1
導(dǎo)入包時(shí)有一個(gè)可以選擇的方式:
from sound.effects import echo
1
這樣就加載了 echo 子模塊,并且使得它在沒(méi)有包前綴的情況下也可以使用,所以它可以如下方式調(diào)用:
echo.echofilter(input, output, delay=0.7, atten=4)
1
還有另一種變體用于直接導(dǎo)入函數(shù)或變量:
from sound.effects.echo import echofilter
1
這樣就又一次加載了 echo 子模塊,但這樣就可以直接調(diào)用它的 echofilter() 函數(shù):
echofilter(input, output, delay=0.7, atten=4)
1
需要注意的是使用 from package import item 方式導(dǎo)入包時(shí),這個(gè)子項(xiàng)(item)既可以是包中的一個(gè)子模塊(或一個(gè)子包),也可以是包中定義的其它命名,像函數(shù)、類或變量。import 語(yǔ)句首先核對(duì)是否包中有這個(gè)子項(xiàng),如果沒(méi)有,它假定這是一個(gè)模塊,并嘗試加載它。如果沒(méi)有找到它,會(huì)引發(fā)一個(gè) ImportError 異常。
相反,使用類似 import item.subitem.subsubitem 這樣的語(yǔ)法時(shí),這些子項(xiàng)必須是包,最后的子項(xiàng)可以是包或模塊,但不能是前面子項(xiàng)中定義的類、函數(shù)或變量。
4.1. 從 * 導(dǎo)入包
那么當(dāng)用戶寫下 from sound.effects import * 時(shí)會(huì)發(fā)生什么事?理想中,總是希望在文件系統(tǒng)中找出包中所有的子模塊,然后導(dǎo)入它們。這可能會(huì)花掉很長(zhǎng)時(shí)間,并且出現(xiàn)期待之外的邊界效應(yīng),導(dǎo)出了希望只能顯式導(dǎo)入的包。
對(duì)于包的作者來(lái)說(shuō)唯一的解決方案就是給提供一個(gè)明確的包索引。import 語(yǔ)句按如下條件進(jìn)行轉(zhuǎn)換:執(zhí)行 from package import * 時(shí),如果包中的 init.py 代碼定義了一個(gè)名為 all 的列表,就會(huì)按照列表中給出的模塊名進(jìn)行導(dǎo)入。新版本的包發(fā)布時(shí)作者可以任意更新這個(gè)列表。如果包作者不想 import * 的時(shí)候?qū)胨麄兊陌兴心K,那么也可能會(huì)決定不支持它( import * )。例如, sound/effects/init.py 這個(gè)文件可能包括如下代碼:
__all__ = ["echo", "surround", "reverse"]
1
這意味著 from sound.effects import * 語(yǔ)句會(huì)從 sound 包中導(dǎo)入以上三個(gè)已命名的子模塊。
如果沒(méi)有定義 all , from sound.effects import * 語(yǔ)句 不會(huì) 從 sound.effects 包中導(dǎo)入所有的子模塊。無(wú)論包中定義多少命名,只能確定的是導(dǎo)入了 sound.effects 包(可能會(huì)運(yùn)行 init.py 中的初始化代碼)以及包中定義的所有命名會(huì)隨之導(dǎo)入。這樣就從 init.py 中導(dǎo)入了每一個(gè)命名(以及明確導(dǎo)入的子模塊)。同樣也包括了前述的 import 語(yǔ)句從包中明確導(dǎo)入的子模塊,考慮以下代碼:
import sound.effects.echoimport sound.effects.surroundfrom sound.effects import *
1
2
3
在這個(gè)例子中,echo 和 surround 模塊導(dǎo)入了當(dāng)前的命名空間,這是因?yàn)閳?zhí)行 from…import 語(yǔ)句時(shí)它們已經(jīng)定義在 sound.effects 包中了(定義了 all 時(shí)也會(huì)同樣工作)。
盡管某些模塊設(shè)計(jì)為使用 import * 時(shí)它只導(dǎo)出符合某種規(guī)范/模式的命名,仍然不建議在生產(chǎn)代碼中使用這種寫法。
記住,from Package import specific_submodule 沒(méi)有錯(cuò)誤!事實(shí)上,除非導(dǎo)入的模塊需要使用其它包中的同名子模塊,否則這是推薦的寫法。
4.2. 包內(nèi)引用
如果包中使用了子包結(jié)構(gòu)(就像示例中的 sound 包),可以按絕對(duì)位置從相鄰的包中引入子模塊。例如,如果 sound.filters.vocoder 包需要使用 sound.effects 包中的 echo 模塊,它可以 from sound.Effects import echo。
你可以用這樣的形式 from module import name 來(lái)寫顯式的相對(duì)位置導(dǎo)入。那些顯式相對(duì)導(dǎo)入用點(diǎn)號(hào)標(biāo)明關(guān)聯(lián)導(dǎo)入當(dāng)前和上級(jí)包。以 surround 模塊為例,你可以這樣用:
from . import echofrom .. import formatsfrom ..filters import equalizer
1
2
3
需要注意的是顯式或隱式相對(duì)位置導(dǎo)入都基于當(dāng)前模塊的命名。因?yàn)橹髂K的名字總是 “main“,Python 應(yīng)用程序的主模塊應(yīng)該總是用絕對(duì)導(dǎo)入。
4.3. 多重目錄中的包
包支持一個(gè)更為特殊的特性, path。 在包的 init.py 文件代碼執(zhí)行之前,該變量初始化一個(gè)目錄名列表。該變量可以修改,它作用于包中的子包和模塊的搜索功能。
這個(gè)功能可以用于擴(kuò)展包中的模塊集,不過(guò)它不常用。
事實(shí)上函數(shù)定義既是“聲明”又是“可執(zhí)行體”;執(zhí)行體由函數(shù)在模塊全局語(yǔ)義表中的命名導(dǎo)入。
每個(gè)模塊都有自己私有的符號(hào)表,被模塊內(nèi)所有的函數(shù)定義作為全局符號(hào)表使用。因此,模塊的作者可以在模塊內(nèi)部使用全局變量,而無(wú)需擔(dān)心它與某個(gè)用戶的全局變量意外沖突。從另一個(gè)方面講,如果你確切的知道自己在做什么,你可以使用引用模塊函數(shù)的表示法訪問(wèn)模塊的全局變量,modname.itemname。
本文版權(quán)歸黑馬程序員人工智能+Python培訓(xùn)學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!
作者:黑馬程序員人工智能+Python培訓(xùn)學(xué)院
首發(fā):http://python.itheima.com/