Python 公用程式

在本節中,我們會介紹一些 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 位址。您可以嘗試透過 wgetcurl 擷取相同網址,進行驗證。如果這些程式也失敗,您就必須透過 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)

運動

如要練習檔案系統和外部指令內容,請參閱「複製特別練習」。如要練習 urllib 內容,請參閱記錄解謎運動