如果你從 Python 解釋器退出然后再進入它尉咕,你所做的定義(函數(shù)和變量)都會消失萍桌。因此抛寝,如果你想寫某些更長的程序项滑,你最好使用一個文本編輯器來為解釋器準備輸入,然后以這個文件作為輸入來運行程序茧球。這也被稱為創(chuàng)建一個 *腳本*庭瑰。當你的程序變得更長,你也許會想將它分成幾個文件方便管理抢埋。你也許還想在幾個程序中直接使用函數(shù)而不用在每個程序中拷貝函數(shù)定義弹灭。
為了支持這種特性,Python 可以把定義放入一個文件中然后在一個腳本或交互式解釋器實例中使用它揪垄。這個文件被叫做 *模塊 (module)*穷吮,模塊中的定義可以通過 *導入* 進入到其他模塊或者 *主* 模塊(你在頂層和計算器模式下執(zhí)行的腳本中可以訪問的變量集合)。
一個模塊是一個包含 Python 定義和聲明的文件饥努。文件是模塊名加上 `.py` 后綴捡鱼。在一個模塊中,模塊名(字符串類型)可以通過全局變量 `__name__` 獲取酷愧。例如驾诈,使用你最喜歡的文本編輯器在當前目錄下創(chuàng)建一個叫 `fibo.py` 的文件,這個文件包含以下內(nèi)容
```python
# 斐波那契數(shù)模塊
def fib(n):? ? # 打印斐波那契數(shù)直到 n
? ? a, b = 0, 1
? ? while a < n:
? ? ? ? print(a, end=' ')
? ? ? ? a, b = b, a+b
? ? print()
def fib2(n):? # 返回到 n 的斐波那契數(shù)
? ? result = []
? ? a, b = 0, 1
? ? while a < n:
? ? ? ? result.append(a)
? ? ? ? a, b = b, a+b
? ? return result
```
現(xiàn)在進入 Python解釋器然后通過下面的命令導入這個模塊
```python
>>> import fibo
```
這樣做不會直接在當前環(huán)境中導入 `fibo` 中定義的函數(shù)名溶浴,只會導入名為 `fibo` 的模塊乍迄。使用模塊名可以獲取模塊中定義的函數(shù):
```python
>>> 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__
'fibo'
```
如果你打算經(jīng)常使用一個函數(shù),你可以把它賦值給一個局部變量
```python
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
1. 模塊進階
--------------------
一個模塊可以包含可執(zhí)行聲明包括函數(shù)定義士败。這些聲明被用于初始化模塊闯两。它們只在模塊被 *第一* 次導入時執(zhí)行。(如果文件被作為腳本運行它們也會被執(zhí)行)
每個模塊都有其私有的符號表谅将,模塊中定義的所有函數(shù)將這個符號表作為全局符號表漾狼。因此,一個模塊的作者可以在模塊中使用全局變量而無需擔心與其他模塊的全部變量沖突戏自。另一方面邦投,如果你知道你在干什么,你同樣可以使用 `模塊.變量` 的方式來獲取一個模塊的全局變量擅笔。
模塊可以導入其他模塊志衣。將所有 [`import`](https://docs.python.org/3/reference/simple_stmts.html#import) 語句放在模塊(或者腳本,如果這個問題重要的話)的開頭不是必須的猛们,但習慣如此念脯。被導入的模塊名被放置于當前模塊的全局符號表中。
[`import`](https://docs.python.org/3/reference/simple_stmts.html#import) 聲明的一種變體可以把一個模塊中的變量直接導入當前模塊的符號表中弯淘。例如:
```python
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
這樣做不會把模塊名引入本地符號表中(因此上面的例子里绿店,`fibo` 沒有被定義)
還有一種導入聲明的變體可以導入一個模塊中定義的所有變量:
```python
>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
這會導入模塊中除了以下劃線(`_`)開頭的所有名稱。大多數(shù)情況下 Python 程序員不使用這個機制,因為它會為解釋器引入一系列位置未知變量假勿,從而有可能覆蓋你已經(jīng)定義的某些變量借嗽。
請注意,一般來說转培,使用 `import *` 導入模塊或包是不受歡迎的恶导,因為這通常會降低代碼可讀性。但在使用交互型解釋器為了減少打字而使用它是允許的浸须。
如果模塊名后緊跟 [`as`](https://docs.python.org/3/reference/compound_stmts.html#as), 那么 [`as`](https://docs.python.org/3/reference/compound_stmts.html#as) 后的變量名會與被導入的模塊名綁定惨寿。
```python
>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
這與 `import fibo` 的方式導入相同,除了模塊現(xiàn)在被命名為 `fib` 而不是 `fibo`删窒。
使用 [`from`](https://docs.python.org/3/reference/simple_stmts.html#from) 時可以使用這個機制達到相同的效果:
```python
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
> #### 注意
>
> 由于性能原因裂垦,每個模塊在每個解釋器會話中只會被導入一次。因此肌索,如果你改變了你的模塊蕉拢,你必須重啟解釋器 -- 或者你只想交互式地測試一個模塊,你可以使用 [`importlib.reload()`](https://docs.python.org/3/library/importlib.html#importlib.reload "importlib.reload")驶社,例如企量,`import importlib;importlib.reload(modulename)`。
### 1.1. 將可執(zhí)行模塊當做腳本
當你這樣使用一個 Python 模塊
```python
python fibo.py <arguments>
```
模塊中的代碼會被執(zhí)行亡电,就如你導入這個模塊一樣,除了 `__name__` 變量被賦值為 `"__main__"`硅瞧。這意味著在模塊的末尾添加下面的代碼:
```python
if __name__ == "__main__":
? ? import sys
? ? fib(int(sys.argv[1]))
```
你可以讓一個文件當成腳本來使用同時也可以將其作為一個可導入模塊份乒,因為代碼會解析命令行,并只在模塊作為 “main” 文件時才會執(zhí)行腕唧。
```python
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
```
如果模塊被導入或辖,代碼不會運行:
```python
>>> import fibo
>>>
```
這經(jīng)常被用于提供模塊的用戶接口或測試(以腳本的形式運行模塊來執(zhí)行某個測試集)
### 1.2. 模塊搜索路徑
當一個名為 `spam` 的模塊被導入時,解釋器首先尋找同名的內(nèi)建模塊枣接。如果沒有發(fā)現(xiàn)同名內(nèi)建模塊颂暇,解釋器會根據(jù) [`sys.path`](https://docs.python.org/3/library/sys.html#sys.path "sys.path") 提供的一系列路徑下尋找名為 `spam.py` 的文件。[`sys.path`](https://docs.python.org/3/library/sys.html#sys.path "sys.path") 根據(jù)下面這些位置進行初始化:
-? 包含輸入腳本的目錄(如果沒有指明文件則為當前目錄)
-? [`PYTHONPATH`](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH) 一個目錄的列表但惶,語法與 shell 的 `PATH` 變量相同耳鸯。
-? 安裝依賴默認路徑
> #### 注意
>
> 在支持符號鏈接的文件系統(tǒng)上,包含輸入腳本的目錄在符號鏈接被跟隨之后才被計算膀曾。換句話說县爬,包含符號鏈接的目錄 **不會** 被添加到模塊搜索路徑。
初始化后添谊,Python 程序會修改 [`sys.path`](https://docs.python.org/3/library/sys.html#sys.path "sys.path")财喳。包含當前運行腳本的目錄會被放在搜索路徑的首位,位于標準庫之前。這意味著該目錄中與標準庫同名的文件將會被導入耳高,而相應的標準庫則不會被導入扎瓶。這將導致錯誤,除非你有意替換泌枪。參考 [Standard Modules](https://docs.python.org/3/tutorial/modules.html#tut-standardmodules) 獲取更多信息栗弟。
### 1.3. “編譯的” Python 文件
為了加快模塊載入速度,Python 將每個模塊的編譯版本以 `module.*version*.pyc` 的名稱緩存在 `__pycache__` 目錄下工闺,"version" 編碼編譯文件的格式乍赫,它通常包含 Python 版本號。例如陆蟆,在 CPython 3.3 編譯的 spam.py 文件緩存在 `__pycache__/spam.cpython-33.pyc` 中雷厂。這種命名方式允許不同發(fā)行版本和不同版本的 Python 編譯文件共存。
Python 檢查源文件修改日期并與編譯的文件進行比較以確認編譯文件是否過時叠殷,需要重新編譯改鲫。這是一個全自動過程。同樣的林束,編譯的模塊不依賴于操作系統(tǒng)像棘,所以相同的庫可以在不同架構(gòu)的系統(tǒng)之間分享。
Python 在兩種情況下不檢查緩存壶冒。首先缕题,Python 總會重新編譯且不會緩存從命令行直接導入模塊。其次胖腾,如果沒有源模塊烟零,Python 也不會檢查緩存。為了支持無源文件(只有編譯文件)發(fā)布咸作,編譯的模塊必須位于源目錄锨阿,且不能有一個源模塊。
對于高階玩家的提醒:
-? 你可以使用 [`-O`](https://docs.python.org/3/using/cmdline.html#cmdoption-o) 或 [`-OO`](https://docs.python.org/3/using/cmdline.html#cmdoption-oo) Python 命令開關來減少一個編譯模塊的大小. `-O` 選項會去除斷言聲明记罚,`-OO` 選項會去除斷言聲明和 `__doc__` 字符串墅诡。由于一些程序依賴于這些變量,請只有在你明確知道自己在干嘛時使用這兩個選項桐智∧┰纾“優(yōu)化” 過的模塊有一個 `opt-` 標簽通常會更小。以后的版本也許會改版優(yōu)化的效果酵使。
-? 從 `.pyc` 文件讀取的程序不會比從 `.py` 文件讀取的程序快荐吉;`.pyc` 只在載入時更快。
-? 模塊 [`compileall`](https://docs.python.org/3/library/compileall.html#module-compileall "compileall: Tools for byte-compiling all Python source files in a directory tree.") 可以在一個目錄下創(chuàng)建所有模塊的 .pyc 文件口渔。
-? 編譯過程還有更多細節(jié)样屠,包括一個決策流程圖,它可以在 [**PEP 3147**](https://www.python.org/dev/peps/pep-3147) 找到。
2. 標準模塊
---------------------
Python 帶有一個標準模塊庫痪欲,并發(fā)布有獨立的文檔悦穿,名為 Python 庫參考手冊(此后稱其為"庫參考手冊")。有一些模塊內(nèi)置于解釋器之中业踢,這些操作的訪問接口不是語言內(nèi)核的一部分栗柒,但是已經(jīng)內(nèi)置于解釋器了。這既是為了提高效率知举,也是為了給系統(tǒng)調(diào)用等操作系統(tǒng)原生訪問提供接口瞬沦。這類模塊集合是一個依賴于底層平臺的配置選項。例如雇锡,[winreg](https://docs.python.org/3/library/winreg.html#module-winreg) 模塊只提供在 Windows 系統(tǒng)上才有逛钻。有一個具體的模塊值得注意: [sys](https://docs.python.org/3/library/sys.html#module-sys) ,這個模塊內(nèi)置于所有的 Python 解釋器锰提。變量 `sys.ps1` 和 `sys.ps2`定義了主提示符和輔助提示符字符串:
```python
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
```python
這兩個變量只在解釋器的交互模式下有意義曙痘。
變量 `sys.path` 是解釋器模塊搜索路徑的字符串列表。它由環(huán)境變量 [PYTHONPATH](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH) 初始化立肘,如果沒有設定 [PYTHONPATH](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH) 边坤,就由內(nèi)置的默認值初始化。你可以用標準的字符串操作修改它:
```python
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
```
3. [`dir()`](https://docs.python.org/3/library/functions.html#dir "dir") 函數(shù)
---------------------------------------------------------------------------------------
內(nèi)置函數(shù) [dir()](https://docs.python.org/3/library/functions.html#dir) 用于按模塊名搜索模塊定義谅年,它返回一個字符串類型的存儲列表:
```python
>>> 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']
```
無參數(shù)調(diào)用時茧痒,[dir()](https://docs.python.org/3/library/functions.html#dir) 函數(shù)返回當前定義的命名:
```python
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
```
注意該列表列出了所有類型的名稱:變量,模塊踢故,函數(shù)文黎,等等。
[dir()](https://docs.python.org/3/library/functions.html#dir) 不會列出內(nèi)置函數(shù)和變量名殿较。如果你想列出這些內(nèi)容,它們在標準模塊 [builtins](https://docs.python.org/3/library/builtins.html#module-builtins) 中定義:
```python
>>> 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']
```
4. 包
-------------
包通常是使用『圓點模塊名』的結(jié)構(gòu)化模塊命名空間桩蓉。例如淋纲,名為 `A.B` 的模塊表示了名為 `A` 的包中名為 `B` 的子模塊。正如同用模塊來保存不同的模塊架構(gòu)可以避免全局變量之間的相互沖突院究,使用圓點模塊名保存像 NumPy 或 Python Imaging Library 之類的不同類庫架構(gòu)可以避免模塊之間的命名沖突洽瞬。
假設你現(xiàn)在想要設計一個模塊集(一個"包")來統(tǒng)一處理聲音文件和聲音數(shù)據(jù)。存在幾種不同的聲音格式(通常由它們的擴展名來標識业汰,例如:`.wav`伙窃, `.aiff`,`.au` )样漆,于是为障,為了在不同類型的文件格式之間轉(zhuǎn)換,你需要維護一個不斷增長的包集合△⒃梗可能你還想要對聲音數(shù)據(jù)做很多不同的操作(例如混音呻右,添加回聲,應用平衡 功能鞋喇,創(chuàng)建一個人造效果)声滥,所以你要加入一個無限流模塊來執(zhí)行這些操作。你的包可能會是這個樣子(通過分級的文件體系來進行分組):
```python
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
? ? ? ? ? ? ? ...
```
當導入這個包時侦香,Python 通過 `sys.path` 搜索路徑查找包含這個包的子目錄落塑。
為了讓 Python 將目錄當做內(nèi)容包,目錄中必須包含 `__init__.py` 文件罐韩。這是為了避免一個含有爛俗名字的目錄無意中隱藏了稍后在模塊搜索路徑中出現(xiàn)的有效模塊憾赁,比如 string。最簡單的情況下伴逸,只需要一個空的 `__init__.py` 文件即可缠沈。當然它也可以執(zhí)行包的初始化代碼,或者定義稍后介紹的 `__all__` 變量错蝴。
用戶可以每次只導入包里的特定模塊洲愤,例如:
```python
import sound.effects.echo
```
這樣就導入了 `sound.effects.echo` 子模塊。它必需通過完整的名稱來引用:
```python
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
```
導入包時有一個可以選擇的方式:
```python
from sound.effects import echo
```
這樣就加載了 `echo` 子模塊顷锰,并且使得它在沒有包前綴的情況下也可以使用柬赐,所以它可以如下方式調(diào)用:
```python
echo.echofilter(input, output, delay=0.7, atten=4)
```
還有另一種變體用于直接導入函數(shù)或變量:
```python
from sound.effects.echo import echofilter
```
這樣就又一次加載了 `echo` 子模塊,但這樣就可以直接調(diào)用它的 `echofilter()` 函數(shù):
```python
echofilter(input, output, delay=0.7, atten=4)
```
需要注意的是使用 `from package import item` 方式導入包時官紫,這個子項(item)既可以是包中的一個子模塊(或一個子包)肛宋,也可以是包中定義的其它命名,像函數(shù)束世、類或變量酝陈。`import` 語句首先核對是否包中有這個子項,如果沒有毁涉,它假定這是一個模塊沉帮,并嘗試加載它。如果沒有找到它贫堰,會引發(fā)一個 [ImportError](https://docs.python.org/3/library/exceptions.html#ImportError) 異常穆壕。
相反,使用類似 `import item.subitem.subsubitem` 這樣的語法時其屏,這些子項必須是包喇勋,最后的子項可以是包或模塊,但不能是前面子項中定義的類偎行、函數(shù)或變量川背。
### 4.1. 使用 * 導入包
那么當用戶寫下 `from sound.effects import *` 時會發(fā)生什么事贰拿?理想中,總是希望在文件系統(tǒng)中找出包中所有的子模塊渗常,然后導入它們壮不。這可能會花掉很長時間,并且出現(xiàn)期待之外的邊界效應皱碘,導出了希望只能顯式導入的包询一。
對于包的作者來說唯一的解決方案就是給提供一個明確的包索引。[import](https://docs.python.org/3/reference/simple_stmts.html#import) 語句按如下條件進行轉(zhuǎn)換:執(zhí)行 `from package import *` 時癌椿,如果包中的 `__init__.py` 代碼定義了一個名為 `__all__` 的列表健蕊,就會按照列表中給出的模塊名進行導入。新版本的包發(fā)布時作者可以任意更新這個列表踢俄。如果包作者不想 `import *` 的時候?qū)胨麄兊陌兴心K缩功,那么也可能會決定不支持它( `import *` )。例如都办, `sound/effects/__init__.py` 這個文件可能包括如下代碼:
```python
__all__ = ["echo", "surround", "reverse"]
```
這意味著 `from sound.effects import *` 語句會從 `sound` 包中導入以上三個已命名的子模塊嫡锌。
如果沒有定義 `__all__` , `from sound.effects import *` 語句 *不會* 從 `sound.effects` 包中導入所有的子模塊琳钉。無論包中定義多少命名势木,只能確定的是導入了 `sound.effects` 包(可能會運行 `__init__.py` 中的初始化代碼)以及包中定義的所有命名會隨之導入。這樣就從 `__init__.py` 中導入了每一個命名(以及明確導入的子模塊)歌懒。同樣也包括了前述的 [import](https://docs.python.org/3/reference/simple_stmts.html#import) 語句從包中明確導入的子模塊啦桌,考慮以下代碼:
```python
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
```
在這個例子中,`echo` 和 `surround` 模塊導入了當前的命名空間及皂,這是因為執(zhí)行 `from...import` 語句時它們已經(jīng)定義在 `sound.effects` 包中了(定義了 `__all__` 時也會同樣工作)甫男。
盡管某些模塊設計為使用 `import *` 時它只導出符合某種規(guī)范/模式的命名,仍然不建議在生產(chǎn)代碼中使用這種寫法验烧。
記住板驳,`from Package import specific_submodule` 沒有錯誤!事實上碍拆,除非導入的模塊需要使用其它包中的同名子模塊笋庄,否則這是推薦的寫法。
### 4.2. 包內(nèi)引用
如果包中使用了子包結(jié)構(gòu)(就像示例中的 `sound` 包)倔监,可以按絕對位置從相鄰的包中引入子模塊。例如菌仁,如果 `sound.filters.vocoder` 包需要使用 `sound.effects` 包中的 `echo` 模塊浩习,它可以 `from sound.Effects import echo`。
你可以用這樣的形式 `from module import name` 來寫顯式的相對位置導入济丘。那些顯式相對導入用點號標明關聯(lián)導入當前和上級包谱秽。以 `surround` 模塊為例洽蛀,你可以這樣用:
```python
from . import echo
from .. import formats
from ..filters import equalizer
```
需要注意的是顯式或隱式相對位置導入都基于當前模塊的命名。因為主模塊的名字總是 `"__main__"`疟赊,Python 應用程序的主模塊應該總是用絕對導入郊供。
### 4.3. 多重目錄中的包
包支持一個更為特殊的特性, [__path__](https://docs.python.org/3/reference/import.html#__path__)近哟。 在包的 `__init__.py` 文件代碼執(zhí)行之前驮审,該變量初始化一個目錄名列表。該變量可以修改吉执,它作用于包中的子包和模塊的搜索功能疯淫。
這個功能可以用于擴展包中的模塊集,不過它不常用戳玫。