在本節中,我們會介紹一些 Python 眾多標準公用程式模組來解決常見問題。
檔案系統 -- os、os.path、closeil
*os* 和 *os.path* 模組包含許多與檔案系統互動的函式。*shutil* 模組可複製檔案。
- os 模組文件
- filenames = os.listdir(dir) -- 該目錄路徑 (不含 .) 的檔案名稱清單和 ..)。檔案名稱僅是目錄中的名稱,而非絕對路徑。
- os.path.join(dir, filename) -- 參考上列清單中的檔案名稱,將此名稱放在一起,以建立路徑
- os.path.abspath(path) -- 指定路徑,就會傳回絕對格式,例如 /home/nick/foo/bar.html
- os.path.dirname(path), os.path.basename(path) --指定的 dir/foo/bar.html 會傳回以下目錄:「dir/foo」和 Basename「bar.html」
- os.path.exists(path) -- true (如果有的話)
- os.mkdir(dir_path) -- 製作一個 dir, os.makedirs(dir_path) 以達成此路徑中所需的全部目錄
- poweril.copy(來源-path, st-path) -- 複製檔案 (目的地路徑目錄必須存在)
## Example pulls filenames from a dir, prints their relative and absolute paths def printdir(dir): filenames = os.listdir(dir) for filename in filenames: print(filename) ## foo.txt print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir) print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt
透過內建的 Python help() 和 dir() 函式,都能順暢探索模組。在解譯器中執行「import os」,然後使用這些指令查看模組中可用的功能:dir(os)、help(os.listdir)、dir(os.path)、help(os.path.dirname)。
執行外部程序 -- 子程序
「子程序」模組是執行外部指令及擷取其輸出內容的簡單方法。
- 子程序模組文件
- output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) -- 執行指令,等候指令結束,並傳回其輸出文字。這個指令的標準輸出和標準錯誤合併成一個輸出文字。如果失敗,系統會擲回 CalledProcessError。
- 如要進一步控制子程序的執行,請參閱 subprocess.popen 類別
- 另有一個簡單的 subprocess.call(cmd) 可用於執行指令,並將輸出內容轉儲到輸出中,並傳回其錯誤代碼。如果您想執行指令,但不需將輸出內容擷取到 Python 資料結構中,就可以使用此方法。
import subprocess ## Given a dir path, run an external 'ls -l' on it -- ## shows how to call an external program def listdir(dir): cmd = 'ls -l ' + dir print("Command to run:", cmd) ## good to debug cmd before actually running it (status, output) = subprocess.getstatusoutput(cmd) if status: ## Error case, print the command's output to stderr and exit sys.stderr.write(output) sys.exit(status) print(output) ## Otherwise do something with the command's output
例外狀況
例外狀況代表執行階段錯誤會暫停在特定行的正常執行,並將控制項轉移至錯誤處理程式碼。本節只會介紹例外狀況最基本的用法。例如執行階段錯誤可能是程式中使用的變數沒有值 (ValueError .。您可能已看過幾次),或是檔案開啟作業錯誤是因為檔案不存在 (IOError)。詳情請參閱例外狀況教學課程,以及查看完整的例外狀況清單。
如果沒有任何錯誤處理程式碼 (目前為止),執行階段例外狀況只會停止程式並顯示錯誤訊息。這是良好的預設行為,您已多次看過這種做法。您可以在程式碼中加入「try/except」結構來處理例外狀況,如下所示:
try: ## Either of these two lines could throw an IOError, say ## if the file does not exist or the read() encounters a low level error. f = open(filename, 'rb') data = f.read() f.close() except IOError: ## Control jumps directly to here if any of the above lines throws IOError. sys.stderr.write('problem reading:' + filename) ## In any case, the code then continues with the line after the try/except
「Try:」區段包含可能會擲回例外狀況的程式碼。「除了:」區段會在發生例外狀況時保留執行的程式碼。如果沒有例外狀況,則系統會略過以下除外:區段 (也就是該程式碼僅供處理錯誤,而非程式碼的「一般」情況)。您可以使用「除非 IOError as e: ..」(也就是指向例外狀況物件) 的語法,藉此取得例外狀況物件本身的指標。
HTTP -- urllib 和 urlparse
*urllib.request* 模組提供網址擷取功能,讓網址看起來就像您可以讀取的檔案。*urlparse* 模組可以拆開並組合網址。
- urllib.request 模組文件
- ufile = urllib.request.urlopen(url) -- 會傳回類似該網址的物件等檔案
- text = ufile.read() -- 可以讀取該檔案,就像是檔案 (readlines() 等等) 一樣
- info = ufile.info() -- 該要求的中繼資料資訊。info.gettype() 是 MIME 類型,例如「text/html」
- Baseurl = ufile.geturl() -- 取得要求的「base」網址,可能因為重新導向而與原始網址不同
- urllib.request.urlretrieve(url, filename) -- 將網址資料下載至指定檔案路徑
- urllib.parse.urljoin(baseurl, url) -- 指定的網址不一定是滿的,以及來自網頁的基礎網址,傳回完整網址。使用上方的 geturl() 提供基準網址。
所有的例外狀況都位於 urllib.error。
from urllib.request import urlopen ## Given a url, try to retrieve it. If it's text/html, ## print its base url and its text. def wget(url): ufile = urlopen(url) ## get file-like object for url info = ufile.info() ## meta-info about the url content if info.get_content_type() == 'text/html': print('base url:' + ufile.geturl()) text = ufile.read() ## read all its text print(text)
上述程式碼運作正常,但如果網址因故無法運作,則不含錯誤處理機制。以下的函式版本新增了 try/except 邏輯,以便在網址作業失敗時輸出錯誤訊息。
如果 urlopen()
似乎沒有回應,就表示您的系統可能不允許直接存取某些 HTTP 位址。您可以嘗試透過 wget
或 curl
擷取相同網址,進行驗證。如果這些程式也失敗,您就必須透過 Proxy 服務擷取 HTTP 內容。本教學課程不包含設定 Proxy 存取權。
## Version that uses try/except to print an error message if the ## urlopen() fails. def wget2(url): try: ufile = urlopen(url) if ufile.info().get_content_type() == 'text/html': print(ufile.read()) except IOError: print('problem reading url:', url)