小段落


6. 模組

如果你離開Python直譯器然後又再打開Python直譯器的話,你會發現你剛才定義的一些東西(函式或變數)都不再存在了。所以說,如果你真的想寫一些比較大型的程式的話,你可能需要有一個文字編輯器來編輯一個檔案,然後再讓Python直譯器來將這個檔案當作輸入(input)來處理。這個過程就是寫腳本( script )的過程。如果你的程式繼續的越來越長的話,你也許會想要把你的程式分成幾個小的檔案,這樣比較方便來維護你的程式。你也許也會希望有一些方便的函式可以讓你自由的用在好幾個程式之中,你又不想要copy這些函式的定義在每個程式之中。

要達到以上的這些目的,Python有一個將定義放在檔案中的方法,你可以之後再在你的script或是互動模式的程式下使用這些存好的定義。這樣的檔案就叫做模組( module )。存在於module之中的定義可以用 imported 放入在其他的module或是主要的 main module之中。(main module是一組你可以在script的最高一級 (top level)部分使用,或是在互動模式中使用的變數)。

一個module就是一個包含有Python的定義及敘述的檔案,檔案的名稱就是module的名稱加上延伸檔名 .py 在後面。在一個module裡面,module的名字(是一個字串)會存在 __name__ 這個變數裡面並當作全域變數(global variable)使用。舉例來說,你可以用你喜歡的文字編輯器打入以下的內容,並將這個檔案存在目前的目錄,並取名為 fibo.py

# Fibonacci numbers module

def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print b,
a, b = b, a+b

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

現在你可以進入Python的直譯器裡面並且import 你剛剛建立的module,其方法如下:

>>> import fibo

這個命令並不會使得所有的 fibo 裡面的函式名稱都寫入目前的符號表(symbol table)裡面,但是會把 fibo 這個module的名字寫在symbol table裡面。 所以,我們現在就可以使用module的名字來呼叫這些我們之前所定義的函式了:

>>> 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'

如果你真的想要只用函式名稱的話,你可以把這些函式名稱設定到另一個local變數去(可以就是函式的名稱):

>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377


6.1 模組(續)

一個module裡面除了放函式的定義之外也可以放可執行的敘述(statement)。這些statement的功用在於初始化(initialize)這個module。這些statement也只有在module 第一次 被import的時候才會被執行。 6.1

每一個模組都有其自己的符號表(symbol table),這個symbol table也就成為在module裡面所定義的函式的全域變數(global variables)。所以說,寫module的人就可以自由的使用這些global variable而不需要擔心會跟module的使用者的global variable有所衝突。從另一方面來說,如果你知道自己在做什麼的話,你也可以跟使用函式一樣的使用module裡面的global variable。其語法為 modname.itemname.

Module可以被import到其他的module裡面。習慣上(並非一定),我們會把所有的 import 的敘述都放在module(或者是script)的最開頭。這樣的話這個被import的module的名稱就會被放在目前這個module的global symbol table裡面了。

有一個變形的方式可以直接import module裡面的變數或函式的名稱進入symbol table裡面。舉例如下:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

這樣做的話並不會使得module的名字被放在目前的symbol table裡面。(所以在上面的例子裡 fibo 是沒有被定義的)。

我們甚至可以一次將所有的在module裡面所定義的名稱都import進來:

>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

這一個寫法會import所有的定義的名稱,除了以底線 ( _ ) 開頭的之外。


6.1.1 尋找模組的路徑

當你import一個叫做 spam 的module時,直譯器會先在目前的目錄尋找一個叫做 spam.py 的檔案,如果沒找到,會再依據定義在 $PYTHONPATH (一個環境變數)裡面的所有路徑來找。 $PYTHONPATH 的語法與設定方法與 $PATH 是一樣的,也就是一連串的目錄路徑的名稱。如果你沒有設定 $PYTHONPATH ,或是在這些目錄當中也找不到的話,直譯器會繼續在一個安裝時預設的目錄來找,在Unix的機器上,通常這個目錄是 .:/usr/local/lib/python

事實上,module的搜尋路徑是依照存在 sys.path 這一個變數中的一個許多路徑名稱組成的list。這個變數當在Python直譯器啟動時,會從輸入的script(或目前的目錄)、 $PYTHONPATH 、以及安裝時設定的預設目錄來讀取所有的目錄。如果你知道自己在做什麼的話,你可以修改這個變數來改變直譯器尋找module的路徑。請參閱之後的標準模組(standard module)一段。

6.1.2 “編譯過的”( ``Compiled'') Python檔案

對於一些小的程式來說,如果使用很多標準的module,而又想加速啟動的過程,你就可以用編譯過的Python檔案。比如你要找 spam.py ,如果在你找到這個檔案的目錄裡ey4又有一個叫做 spam.pyc 的檔案的話,這就表示 spam 這個module有一個已經二元編譯過的(``byte-compiled'')的版本可以使用。在 spam.pyc 裡面也會記錄用來創造它的spam.py上一次被修改的時間,如果 .pyc 裡面所儲存的時間與最新版本的 .py 的修改時間不符合的話, .pyc 檔案就不會被使用。

一般來說,你不需要做任何事來創造一個 spam.pyc 檔案。當你成功的編譯一個 spam.py 檔時,自動的 spam.pyc 檔就會寫入在同一個目錄裡。如果這個過程裡有問題的話,系統不會當這是個錯誤情況(error)。相反的,如果寫入的檔案沒有完全成功的寫入的話,這個檔案只會被認為是不正確的而忽視其存在。 spam.pyc 檔案的內容是獨立於作業系統平台的,所以一個 Python module 的目錄是可以被在各種不同架構下的多台機器所共享的。

這裡有一些給專家們的秘訣:


6.2 標準模組

Python包含有一個 標準模組的程式庫,這個程式庫在另一個文件 Python Library Reference (Python程式庫參考手冊)中有更多的描述。有些標準模組已經內建在直譯器裡面,這些模組讓我們可以使用那些不在Python語言本身的一些功能,不管是為了效率或是要使用作業系統的資源(例如system call)。有些module是在設定時的選項,比如說, amoeba 這個module就只有在你的系統裡面有Amoeba相關的資源時才會出現。有一個module特別值得我們好好注意: sys 。這個module在每一個Python直譯器裡面都有,其中有兩個變數 sys.ps1 以及 sys.ps2 是用來設定primary prompt 以及secondary prompt的:

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print 'Yuck!'
Yuck!
C>

這兩個變數只有在當你在互動模式下啟動直譯器時才有定義。

sys.path 這個變數是一個許多目錄路徑組成的list,裡面的目錄路徑就是直譯器尋找module的路徑。這個變數裡面的路徑都是從環境變數 $PYTHONPATH 裡面複製的,或者當 $PYTHONPATH 沒有設定時,就會使用預設值。你也可以用一般使用list的方法來修改之。例如:

>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')


6.3 dir() 函式

內建的 dir() 函式主要是用來找出某個module裡面所定義的所有名稱。其傳回值是一串經過排序了的字串list:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__name__', 'argv', 'builtin_module_names', 'copyright', 'exit',
'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile', 'settrace',
'stderr', 'stdin', 'stdout', 'version']

如果沒有傳入參數的話, dir() 會列出所有你目前已經定義的名稱:

>>> a = [1, 2, 3, 4, 5]
>>> import fibo, sys
>>> fib = fibo.fib
>>> dir()
['__name__', 'a', 'fib', 'fibo', 'sys']

注意這裡的名稱是指所有類型的名稱:包括變數,函式,以及module等等。

dir() 並沒有列出所有內建的函式及變數的名稱。如果你真想要列出來的話,它們都定義在 __builtin__ 這個標準module裡面:

>>> import __builtin__
>>> dir(__builtin__)
['AccessError', 'AttributeError', 'ConflictError', 'EOFError', 'IOError',
'ImportError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
'MemoryError', 'NameError', 'None', 'OverflowError', 'RuntimeError',
'SyntaxError', 'SystemError', 'SystemExit', 'TypeError', 'ValueError',
'ZeroDivisionError', '__name__', 'abs', 'apply', 'chr', 'cmp', 'coerce',
'compile', 'dir', 'divmod', 'eval', 'execfile', 'filter', 'float',
'getattr', 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'len', 'long',
'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range', 'raw_input',
'reduce', 'reload', 'repr', 'round', 'setattr', 'str', 'type', 'xrange']


6.4 Packages(包裝)

Package是一種用點號表示模組名稱(``dotted module names'')的組織Python 模組(module)命名空間的方法。舉例來說:如果module的名稱是 A.B 表示是在 " B" 這個package裡面的一個名稱為 "A" 的module。就如同使用module使得其他寫module的不用擔心別人的global variable命名的問題,使用這種帶點號的module名稱也使得寫多個module的package的人不用擔心所用的module名稱會和別人有所重複。

現在假設你要設計一組的module(就是設計一個package),這個package是用來標準化的處理聲音檔案以及聲音的資料的。由於聲音檔的格式有很多(通常是由其延伸檔名來辨別,例如 .wav, .aiff, .au) 等格式),你也許需要一個隨時會增加新module的package來處理新的聲音檔格式。由於你可能想對聲音資料做各種不同的處理(例如混音、加迴聲、加入平衡方程式,加入人工音響效果等等),所以你還需要寫一些module來專門做這些處理。底下這個架構可能是你的package所需要的(用檔案階層系統來表示):

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能把這個目錄架構當作是一個package,上面的 __init__.py 這個檔是必須要的。這是為了要避免有些檔案目錄的名字是很普通的名字(例如 " string" ),這會讓直譯器誤認正確的module名稱而找不到在搜尋路徑中的module。在最簡單的例子裡, __init__.py 可以是一個空的檔案。但是你也可以讓這個檔來做一些package初始化的動作,或者設定 __all__ 這個變數(稍後會再提)。

使用package的人可以從package裡使用(import)某一個module,例如:

import Sound.Effects.echo

上面的程式碼會導入(load) Sound.Effects.echo 這個module。如果你要使用這個module,你必須使用完整的名稱,例如:

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

另外一個導入在package中的某個module的方法是:

from Sound.Effects import echo

同樣的,這會導入 echo 這個moduel。不同的是,當你使用這個module的時候你就不用在寫前面package的名稱了。請看以下使用這個module的例子:

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

你也可以直接的import某一個在module裡面的函式或變數,如下例:

from Sound.Effects.echo import echofilter

同樣的,這會導入 echo 這個module,不同的是你現在可以直接的使用 echofilter() 這個函式了:

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

值得注意的是當你使用 from package import item 這樣的敘述時,你所import的東西可以是一個package中的module(或者是subpackage),或者是在module裡面所定義的名稱,例如變數、類別或是函式等等。 import 敘述會先測試是否這個東西真的存在於這個package,如果沒有的話,會假設這是一個module然後試著導入(load)之。如果還失敗的話,就會引發一個 ImportError 的例外狀況(exception)。

相反的是,當你使用 import item.subitem.subsubitem 這樣的敘述時,除了最後一個東西(item)以外,其餘的都必須是package。最後一個可以是 module 或是 package ,但是不能是一個定義在module裡面的類別、成員或函式。


6.4.1 從一個Package中Import *

那如果使用者寫了 from Sound.Effects import * ,會造成什麼結果呢?理想狀況下,我們可能會期望會搜尋整個package目錄,然後找出所有的module並且一一的import這些module。不幸的是,在Mac 以及 Windows 平台下,檔案的名稱大小寫並不統一。所以在這些平台之上,我們並無法保證 ECHO.PY 這個檔案應該被import成 echo, EchoECHO (例如,Windows 95 有一個惱人的特點,就是會自動把所有的檔案名稱第一個字元大寫)。DOS的 8+3 檔名限制對長的module名稱來說,也是另一個有趣的問題。

所以唯一的解決方法就是package的作者要提供一個明顯的index給用package的人。如果遵守這個習慣的話,當用package的人在import的時候使用 from Sound.Effects import * 的話,就會去找這個package的 __init__.py 檔案裡面的 __all__ 這個list變數,這個list裡面就會包含所有應該被import進來的module名稱了。身為Package的作者有責任要保持 from package import * 這個檔案的更新,但是如果package的作者確信沒有人會用 from Sound.Effects import * 這種寫法的話,也可以不使用這個檔案。舉例來說 Sounds/Effects/__init__.py 這個檔案就可以有下面這樣的程式碼:

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

這就表示 from Sound.Effects import * 會從 Sound 這個package 裡面import 這三個module。

如果沒有定義 __all__ 的話, from Sound.Effects import * 這個敘述就 不會Sound.Effects 這個package裡面import所有的module進入目前的命名空間(namespace)。唯一能保證的是 Sound.Effects 這個package有被imported 進來(可能會執行 __init__.py 裡面的初始化程式碼),並且這個package裡面所定義的名稱會被import進來。Package裡所定義的名稱包含了在 __init__.py 裡面所定義的名稱(以及所import的module)。當然也包含了在之前用import引進來的module名稱,例如:

import Sound.Effects.echo
import Sound.Effects.surround
from Sound.Effects import *

在這個例子裡,echo以及 surround 這兩個modules 都會被 import進來目前的命名空間(namespace)裡。這是因為當 from...import 這個敘述執行的時候,這兩個module都已經在這個package中有定義了(你也可以用 __all__ 來定義)。

值得注意的是使用import * 這樣的寫法常常是不被鼓勵的,因為這通常會使得你的程式的可讀性降低。無論如何,在互動模式下這樣做的確會使你減少打太多字的機會,而且有些的module在設計的時候就故意只讓某些特別的名稱可以被使用。

記住,使用 from Package import specific_submodule 沒有任何不對的地方。事實上,除非你的module的名字會和其他的名稱衝突,否則這是常被推薦使用的形式。

6.4.2 Package內的References(參考)

在package之中的module常常需要彼此互相使用。例如說, surround 這個module就有可能會使用到 echo 這個module裡的東西。事實上,由於這是最常見的,所以import的時候總是會先找自己這的package裡面的module,然後再依照搜尋的路徑來尋找。因此 surround 這個module可以使用 import echo 或是 from echo import echofilter 就可以了。如果在自己所處的這個package裡面找不到這個要import的module的話, import 指令就會在第一級(top-level)的module裡找所指定的名稱。

當一個subpackage是在另一個package裡的話(例如前面的 Sound ),沒有其他捷徑可以讓你使用其他在同一個外圍的package裡面的subpackage裡的module,你必須使用完整的名稱來指稱你所要用的package。例如說,如果在 Sound.Filters.vocoder 這個module裡面你想要使用在 Sound.Effects 這個package裡的 echo 這個module的話,你就要使用 from Sound.Effects import echo 這個敘述。



註腳

... 才會被執行。 6.1
事實上,函式的定義也是”被執行”的敘述,這個執行的結果是把函式的名稱寫入module的global symbol table裡面。

請看 關於此文件… 裡面有關如何給我們建議的說明。