6. 模組(Module) — Python 3.10.6 說明文件

文章推薦指數: 80 %
投票人數:10人

Import 套件時,Python 會搜尋 sys.path 裡的目錄,尋找套件的子目錄。

目錄中必須含有 __init__.py 檔案,才會被Pyhon 當成套件;這樣可以避免一些以常用名稱 ... 瀏覽 索引 模組| 下一頁| 上一頁| Python» 3.10.6Documentation» Python教學» 6.模組(Module) | 6.模組(Module)¶ 如果從Python直譯器離開後又再次進入,之前(幫函式或變數)做的定義都會消失。

因此,想要寫一些比較長的程式時,你最好使用編輯器來準備要輸入給直譯器的內容,並且用該檔案來運行它。

這就是一個腳本(script)。

隨著你的程式越變越長,你可能會想要把它分開成幾個檔案,讓它比較好維護。

你可能也會想用一個你之前已經在其他程式寫好的函式,但不想要複製該函式的原始定義到所有使用它的程式裡。

為了支援這一點,Python有一種方法可以將定義放入檔案中,並在互動模式下的直譯器中使用它們。

這種檔案稱為模組(module);模組中的定義可以被import到其他模組中,或是被import至主(main)模組(在最頂層執行的腳本,以及互動模式下,所使用的變數集合)。

模組是指包含Python定義和語句的檔案,檔案名稱是模組名稱加上.py。

在模組中,模組的名稱(作為字串)會是全域變數__name__的值。

例如,用您喜歡的文字編輯器在資料夾中創一個名為fibo.py的檔案,內容如下: #Fibonaccinumbersmodule deffib(n):#writeFibonacciseriesupton a,b=0,1 whilea>>importfibo 這並不會將fibo中定義的函式名稱直接加入當前的namespace中(詳情請見Python作用域(Scope)及命名空間(Namespace));它只會加入fibo的模組名稱。

使用此模組名稱,就可以存取函式: >>>fibo.fib(1000) 01123581321345589144233377610987 >>>fibo.fib2(100) [0,1,1,2,3,5,8,13,21,34,55,89] >>>fibo.__name__ 'fibo' 如果您打算經常使用其中某個函式,可以將其指定至區域變數: >>>fib=fibo.fib >>>fib(500) 01123581321345589144233377 6.1.深入了解模組¶ 模組可以包含可執行的陳述式以及函式的定義。

這些陳述式是作為模組的初始化,它們只會在第一次被import時才會執行。

1(如果檔案被當成腳本執行,也會執行它們)。

每個模組都有它自己的私有命名空間(namespace),模組內定義的函式會把該模組的私有符號表當成全域命名空間使用。

因此,模組的作者可以在模組中使用全域變數,而不必擔心和使用者的全域變數發生意外的名稱衝突。

另一方面,如果你知道自己在做什麼,你可以用這個方式取用模組的全域變數,以和引用函式一樣的寫法,modname.itemname。

在一個模組中可以import其他模組。

把所有的import陳述式放在模組(就這邊來說,腳本也是一樣)的最開頭是個慣例,但並沒有強制。

如放置在模組的最高層(不在任何函式或class中),被import的模組名稱將被加入全域命名空間中。

import陳述式有另一種變形寫法,可以直接將名稱從欲import的模組,直接import至原模組的命名空間中。

例如: >>>fromfiboimportfib,fib2 >>>fib(500) 01123581321345589144233377 在import之後的名稱會被導入,但定義該函式的整個模組名稱並不會被引入在區域命名空間中(因此,示例中的fibo未被定義)。

甚至還有另一種變形寫法,可以import模組定義的所有名稱: >>>fromfiboimport* >>>fib(500) 01123581321345589144233377 這個寫法會import模組中所有的名稱,除了使用底線(_)開頭的名稱。

大多數情況下,Python程式設計師不大使用這個功能,因為它在直譯器中引入了一組未知的名稱,並且可能覆蓋了某些您已經定義的內容。

請注意,一般情況下並不建議從模組或套件中import*的做法,因為它通常會導致可讀性較差的程式碼。

但若是使用它來在互動模式中節省打字時間,則是可以接受的。

如果模組名稱後面出現as,則as之後的名稱將直接和被import模組綁定在一起。

>>>importfiboasfib >>>fib.fib(500) 01123581321345589144233377 這個import方式和importfibo實質上是一樣的,唯一的差別是現在要用fib使用模組。

在使用from時也可以用同樣的方式獲得類似的效果: >>>fromfiboimportfibasfibonacci >>>fibonacci(500) 01123581321345589144233377 備註 出於效率原因,每個模組在每個直譯器session中僅會被import一次。

因此,如果您更改了模組,則必須重啟直譯器——或者,如果只是一個想要在互動模式下測試的模組,可以使用importlib.reload()。

例如:importimportlib;importlib.reload(modulename)。

6.1.1.把模組當作腳本執行¶ 當使用以下內容運行Python模組時: pythonfibo.py 如同使用import指令,模組中的程式碼會被執行,但__name__被設為"__main__"。

這意味著,透過在模組的末尾添加以下程式碼: if__name__=="__main__": importsys fib(int(sys.argv[1])) 你可以將檔案作為腳本也同時可以作為被import的模組,因為剖析(parse)命令列的程式碼只會在當模組是「主」檔案時,才會執行: $pythonfibo.py50 0112358132134 如果此模組是被import的,則該段程式碼不會被執行: >>>importfibo >>> 這通常是用來為模組提供方便的使用者介面,或者用於測試目的(執行測試套件時,以腳本的方式執行模組)。

6.1.2.模組的搜尋路徑¶ Import一個名為spam的模組時,直譯器首先會搜尋具有該名稱的內建模組。

模組名稱列在sys.builtin_module_names當中。

如果找不到,接下來會在變數sys.path所給定的資料夾清單之中,搜尋一個名為spam.py的檔案。

sys.path從這些位置開始進行初始化: 輸入腳本所位在的資料夾(如未指定檔案時,則是當前資料夾)。

PYTHONPATH(一連串和shell變數PATH的語法相同的資料夾名稱)。

與安裝相關的預設值(按慣例會包含一個site-packages資料夾,它是由site模組所處理)。

備註 在支援符號連結(symlink)的檔案系統中,輸入腳本的所在資料夾是在跟隨符號連結之後才被計算的。

換言之,包含符號連結的資料夾並沒有增加到模組的搜尋路徑中。

初始化之後,Python程式可以修改sys.path。

執行中腳本的所在資料夾會在搜尋路徑的開頭,在標準函式庫路徑之前。

這代表該資料夾中的腳本會優先被載入,而不是函式庫資料夾中相同名稱的模組。

除非是有意要做這樣的替換,否則這是一個錯誤。

請參見標準模組以瞭解更多資訊。

6.1.3.「編譯」Python檔案¶ 為了加快載入模組的速度,Python將每個模組的編譯版本暫存在__pycache__資料夾下,並命名為module.version.pyc,這裡的version是編譯後的檔案的格式名稱,且名稱通常會包含Python的版本編號。

例如,在CPython3.3中,spam.py的編譯版本將被暫存為__pycache__/spam.cpython-33.pyc。

此命名準則可以讓來自不同版本的編譯模組和Python的不同版本同時共存。

Python根據原始碼最後修改的日期,檢查編譯版本是否過期而需要重新編譯。

這是一個完全自動的過程。

另外,編譯後的模組獨立於平台,因此不同架構的作業系統之間可以共用同一函式庫。

Python在兩種情況下不檢查快取(cache)。

首先,它總是重新編譯且不儲存直接從命令列載入的模組的結果。

第二,如果沒有源模組,則不會檢查快取。

要支援非源模組(僅編譯)的發布,編譯後的模組必須位於原始資料夾中,並且不能有源模組。

一些給專家的秘訣: 可以在Python指令上使用開關參數(switch)-O或-OO來減小已編譯模組的大小。

開關參數-O刪除assert(斷言)陳述式,而-OO同時刪除assert陳述式和__doc__字串。

由於有些程式可能依賴於上述這些內容,因此只有在您知道自己在做什麼時,才應使用此參數。

「已優化」模組有opt-標記,且通常較小。

未來的版本可能會改變優化的效果。

讀取.pyc檔案時,程式的執行速度並不會比讀取.py檔案快。

唯一比較快的地方是載入的速度。

模組compileall可以為資料夾中的所有模組創建.pyc檔。

更多的細節,包括決策流程圖,請參考PEP3147。

6.2.標準模組¶ Python附帶了一個標準模組庫,詳細的介紹在另一份文件,稱為「Python函式庫參考手冊」(簡稱為「函式庫參考手冊」)。

有些模組是直譯器中內建的;它們使一些不屬於語言核心但依然內建的運算得以存取,其目的是為了提高效率,或提供作業系統基本操作(例如系統呼叫)。

這些模組的集合是一個組態選項,它們取決於底層平台。

例如:winreg模組僅供Windows使用。

值得注意的模組是sys,它被內建在每個Python直譯器中。

變數sys.ps1和sys.ps2則用來定義主、次提示字元的字串: >>>importsys >>>sys.ps1 '>>>' >>>sys.ps2 '...' >>>sys.ps1='C>' C>print('Yuck!') Yuck! C> 只有直譯器在互動模式時,才需要定義這兩個變數。

變數sys.path是一個字串list,它決定直譯器的模組搜尋路徑。

它的初始值為環境變數PYTHONPATH中提取的預設路徑,或是當PYTHONPATH未設定時,從內建預設值提取。

你可以用標準的list操作修改該變數: >>>importsys >>>sys.path.append('/ufs/guido/lib/python') 6.3.dir()函式¶ 內建函式dir()用於找出模組定義的所有名稱。

它回傳一個排序後的字串list: >>>importfibo,sys >>>dir(fibo) ['__name__','fib','fib2'] >>>dir(sys) ['__breakpointhook__','__displayhook__','__doc__','__excepthook__', '__interactivehook__','__loader__','__name__','__package__','__spec__', '__stderr__','__stdin__','__stdout__','__unraisablehook__', '_clear_type_cache','_current_frames','_debugmallocstats','_framework', '_getframe','_git','_home','_xoptions','abiflags','addaudithook', 'api_version','argv','audit','base_exec_prefix','base_prefix', 'breakpointhook','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','get_asyncgen_hooks','get_coroutine_origin_tracking_depth', 'getallocatedblocks','getdefaultencoding','getdlopenflags', 'getfilesystemencodeerrors','getfilesystemencoding','getprofile', 'getrecursionlimit','getrefcount','getsizeof','getswitchinterval', 'gettrace','hash_info','hexversion','implementation','int_info', 'intern','is_finalizing','last_traceback','last_type','last_value', 'maxsize','maxunicode','meta_path','modules','path','path_hooks', 'path_importer_cache','platform','prefix','ps1','ps2','pycache_prefix', 'set_asyncgen_hooks','set_coroutine_origin_tracking_depth','setdlopenflags', 'setprofile','setrecursionlimit','setswitchinterval','settrace','stderr', 'stdin','stdout','thread_info','unraisablehook','version','version_info', 'warnoptions'] 沒有給引數時,dir()列出目前已定義的名稱: >>>a=[1,2,3,4,5] >>>importfibo >>>fib=fibo.fib >>>dir() ['__builtins__','__name__','a','fib','fibo','sys'] 請注意,它列出所有類型的名稱:變數、模組、函式等。

dir()不會列出內建函式和變數的名稱。

如果你想要列出它們,它們被定義在標準模組builtins內: >>>importbuiltins >>>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'] 6.4.套件(Package)¶ 套件是一種使用「點分隔模組名稱」組織Python模組命名空間的方法。

例如,模組名稱A.B表示套件A中名為B的子模組。

正如模組使用時,不同模組的作者不需擔心與其他模組的全域變數名稱重複,點分隔模組名稱的使用,也讓多模組套件(像NumPy或Pillow)的作者們不須擔心其他套件的模組名稱。

假設你想設計一個能統一處理音訊檔案及音訊數據的模組集(「套件」)。

因為音訊檔案有很多的不同的格式(通常以它們的副檔名來辨識,例如:.wav,.aiff,.au),因此,為了不同檔案格式之間的轉換,你會需要建立和維護一個不斷增長的模組集合。

為了要達成對音訊數據的許多不同作業(例如,音訊混合、增加回聲、套用等化器功能、創造人工立體音效),你將編寫一系列無止盡的模組來執行這些作業。

以下是你的套件可能的架構(以階層式檔案系統的方式表示): sound/Top-levelpackage __init__.pyInitializethesoundpackage formats/Subpackageforfileformatconversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/Subpackageforsoundeffects __init__.py echo.py surround.py reverse.py ... filters/Subpackageforfilters __init__.py equalizer.py vocoder.py karaoke.py ... Import套件時,Python會搜尋sys.path裡的目錄,尋找套件的子目錄。

目錄中必須含有__init__.py檔案,才會被Pyhon當成套件;這樣可以避免一些以常用名稱命名(例如string)的目錄,無意中隱藏了較晚出現在模組搜尋路徑中的有效模組。

在最簡單的情況,__init__.py可以只是一個空白檔案;但它也可以執行套件的初始化程式碼,或設置__all__變數,之後會詳述。

套件使用者可以從套件中import個別模組,例如: importsound.effects.echo 這樣就載入了子模組sound.effects.echo。

引用時必須用它的全名: sound.effects.echo.echofilter(input,output,delay=0.7,atten=4) 另一種import子模組的方法是: fromsound.effectsimportecho 這段程式碼一樣可以載入子模組echo,並且不加套件前綴也可以使用,因此能以如下方式使用: echo.echofilter(input,output,delay=0.7,atten=4) 另一種變化是直接import所需的函式或變數: fromsound.effects.echoimportechofilter 同樣地,這樣也會載入子模組echo,但它的函式echofilter()就可以直接使用: echofilter(input,output,delay=0.7,atten=4) 請注意,使用frompackageimportitem時,item可以是套件的子模組(或子套件),也可以是套件中被定義的名稱,像是函式、class(類別)或變數。

import陳述式首先測試套件中有沒有定義該item;如果沒有,則會假設它是模組,並嘗試載入。

如果還是找不到item,則會引發ImportError例外。

相反地,使用importitem.subitem.subsubitem語法時,除了最後一項之外,每一項都必須是套件;最後一項可以是模組或套件,但不能是前一項中定義的class、函式或變數。

6.4.1.從套件中import*¶ 當使用者寫下fromsound.effectsimport*時,會發生什麼事?理想情況下,我們可能希望程式碼會去檔案系統,尋找套件中存在的子模組,並將它們全部import。

這會花費較長的時間,且import子模組的過程可能會有不必要的副作用,這些副作用只有在明確地import子模組時才會發生。

唯一的解法是由套件作者為套件提供明確的索引。

import陳述式使用以下慣例:如果套件的__init__.py程式碼有定義一個名為__all__的list,若遇到frompackageimport*的時候,它就會是要被import的模組名稱。

發布套件的新版本時,套件作者可自行決定是否更新此list。

如果套件作者認為沒有人會從他的套件中import*,他也可能會決定不支援這個list。

舉例來說,sound/effects/__init__.py檔案可包含以下程式碼: __all__=["echo","surround","reverse"] 意思是,fromsound.effectsimport*將會importsound.effects套件中,這三個被提名的子模組。

如果__all__沒有被定義,fromsound.effectsimport*陳述式並不會把sound.effects套件中所有子模組都import到當前的命名空間;它只保證sound.effects套件有被import(可能會運行__init__.py中的初始化程式碼),然後import套件中被定義的全部名稱。

這包含__init__.py定義(以及被明確載入的子模組)的任何名稱。

它也包括任何之前被import陳述式明確載入的套件子模組。

請看以下程式碼: importsound.effects.echo importsound.effects.surround fromsound.effectsimport* 此例中,當from...import陳述式被執行時,echo和surround模組被import進當前的命名空間,因為它們是在sound.effects套件裡定義的。

(當__all__有被定義時,這規則也有效。

) 雖然,有些特定模組的設計,讓你使用import*時,該模組只會輸出遵循特定樣式的名稱,但在正式環境(production)的程式碼中這仍然被視為是不良習慣。

記住,使用frompackageimportspecific_submodule不會有任何問題!實際上,這是推薦用法,除非import的模組需要用到的子模組和其他套件的子模組同名。

6.4.2.套件內引用¶ 當套件的結構為多個子套件的組合時(如同範例中的sound套件),可以使用「絕對(absolute)import」,引用同層套件中的子模組。

例如,要在sound.filters.vocoder模組中使用sound.effects中的echo模組時,可以用fromsound.effectsimportecho。

你也可以用frommoduleimportname的import陳述式,編寫「相對(relative)import」。

這些import使用前導句號指示相對import中的當前套件和母套件。

例如,在surround模組中,你可以使用: from.importecho from..importformats from..filtersimportequalizer 請注意,相對import的運作是以目前的模組名稱為依據。

因為主模組的名稱永遠是"__main__",所以如果一個模組預期被用作Python應用程式的主模組,那它必須永遠使用絕對import。

6.4.3.多目錄中的套件¶ 套件也支援一個特殊屬性__path__。

它在初始化時是一個list,包含該套件的__init__.py檔案所在的目錄名稱,初始化時機是在這個檔案的程式碼被執行之前。

這個變數可以被修改,但這樣做會影響將來對套件內的模組和子套件的搜尋。

雖然這個特色不太常被需要,但它可用於擴充套件中的模組集合。

註解 1 實際上,函式定義也是「被執行」的「陳述式」;在執行模組階層的函式定義時,會將函式名稱加到模組的全域命名空間。

目录 6.模組(Module) 6.1.深入了解模組 6.1.1.把模組當作腳本執行 6.1.2.模組的搜尋路徑 6.1.3.「編譯」Python檔案 6.2.標準模組 6.3.dir()函式 6.4.套件(Package) 6.4.1.從套件中import* 6.4.2.套件內引用 6.4.3.多目錄中的套件 上個主題 5.資料結構 下個主題 7.輸入和輸出 此頁面 回報錯誤 顯示原始碼 瀏覽 索引 模組| 下一頁| 上一頁| Python» 3.10.6Documentation» Python教學» 6.模組(Module) |



請為這篇文章評分?