Python 公用程式

在本節中,我們將探討 Python 的許多標準公用程式模組,以解決常見問題。

檔案系統 -- os、os.path、closeil

*os* 和 *os.path* 模組包含許多與檔案系統互動的功能。*shutil* 模組可以複製檔案。

  • OS 模組文件
  • filenames = os.listdir(dir) -- 該目錄路徑 (不含 .和 ..)。檔案名稱只是目錄中的名稱,不是絕對路徑。
  • os.path.join(dir, filename) -- 從上述清單中指定檔案名稱,使用這個檔案將 dir 與檔案名稱結合形成路徑
  • os.path.abspath(path) -- 如果是指定路徑,則傳回絕對格式,例如/home/nick/foo/bar.html
  • os.path.dirname(path), os.path.basename(path) --指定 dir/foo/bar.html,傳回 dirname「dir/foo」基礎名稱則是「bar.html」
  • os.path.exists(path) -- true (如果有的話)
  • os.mkdir(dir_path) -- 建立一個 dir, os.makedirs(dir_path) 一個 dir,所以這個路徑中的所有必要目錄。
  • poweril.copy(source-path, dest-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:
    ## 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 為 e: ..」的語法,取得例外狀況物件本身的指標。(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 內容 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務本教學課程不會說明如何設定 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 教材,請參閱「Log Puzzle Exercise」。