返回文章列表

Python命令列應用程式開發

本文探討 Python 命令列應用程式開發的技巧,涵蓋 argparse、docopt、Click、Clint 和 Cliff 等工具函式庫的使用方法,並比較它們的優缺點,提供程式碼範例和詳細說明,幫助開發者根據專案需求選擇合適的工具,同時也介紹了 GUI 開發的常用工具包。

Python 開發工具

Python 提供豐富的函式庫和框架,簡化命令列應用程式開發。本文介紹 argparse、docopt、Click、Clint 和 Cliff 等工具,並比較它們的特性與使用場景。argparse 適合處理標準命令列引數,docopt 則從檔案字串解析,Click 提供高度可組裝性,Clint 增強命令列介面顯示效果,Cliff 適用於複雜多層級命令結構。開發者可根據專案規模和需求選擇合適的工具,提升開發效率。此外,文章也簡述 GUI 開發的常用 Python 工具包,方便讀者進一步探索。

命令列應用程式

命令列應用程式(Command-line Applications)是指設計用於從文字介面(如 shell)使用的電腦程式。它們可以是簡單的命令,例如 pep8virtualenv,也可以是互動式的,如 Python 直譯器或 ipython。某些命令列應用程式具有子命令,例如 pip installpip uninstallpip freeze,這些子命令除了擁有 pip 的一般選項外,還有自己的選項。所有這些應用程式都可能在 main() 函式中啟動;我們的 BDFL(終身仁慈獨裁者)已經分享了他對什麼是好的 main() 函式的看法。

讓我們使用一個 pip 呼叫的範例來說明呼叫命令列應用程式時可能存在的元件:

$ pip install --user -r requirements.txt

在這個範例中:

  • pip 是被呼叫的可執行檔名稱,即命令。
  • install 是引數或子命令。
  • --user-r requirements.txt 是選項或旗標。

命令列工具函式庫

表格 7-1 中列出的函式庫都為解析命令列引數提供了不同的選項,或為命令列應用程式提供了其他有用的工具。

表格 7-1. 命令列工具

函式庫名稱授權條款使用理由
argparsePSF 授權• 內建於 Python 標準函式庫。
• 提供標準的引數和選項解析功能。
docoptMIT 授權• 允許控制幫助訊息的佈局。
• 根據 POSIX 標準定義的實用工具慣例解析命令列。
placBSD 3-條款授權• 從現有的函式簽名自動生成幫助訊息。
• 在幕後解析命令列引數,並直接將它們傳遞給你的函式。
clickBSD 3-條款授權• 提供裝飾器來製作幫助訊息和解析器(與 plac 類別似)。
• 允許組合多個子命令。
• 與其他 Flask 外掛程式介面(Click 獨立於 Flask,但最初是為了幫助使用者組合來自不同 Flask 外掛程式的命令列工具而不破壞任何東西而編寫的,因此它已經在 Flask 生態系統中使用)。
clint網際網路軟體聯盟(ISC)授權• 為你的文字輸出提供格式化功能,如顏色、縮排和欄位顯示。
• 在互動式輸入中提供型別檢查(例如,檢查正規表示式、整數或路徑)。
• 提供直接存取引數列表的功能,並具有一些簡單的篩選和分組工具。
cliffApache 2.0 授權• 為具有多個子命令的大型 Python 專案提供結構化的框架。
• 建立一個互動式環境來使用子命令,無需額外的編碼。

通常,你應該首先嘗試使用 Python 標準函式庫中提供的工具,只有當它們無法滿足你的需求時,才將其他函式庫新增到你的專案中。

argparse

argparse 模組(取代了現在已棄用的 optparse)存在於 Python 的標準函式庫中,用於幫助解析命令列選項。HowDoI 專案提供的命令列介面使用了 argparse;在建立你自己的命令列介面時,可以參考它。

argparse 使用範例

import argparse

def get_parser():
    parser = argparse.ArgumentParser(description='...為了簡潔而截斷...')
    parser.add_argument('query', metavar='QUERY', type=str, nargs='*',
                        help='要回答的問題')
    parser.add_argument('-p','--pos',
                        help='選擇指定位置的答案(預設:1)',
                        default=1, type=int)
    parser.add_argument('-a','--all', help='顯示答案的全文',
                        action='store_true')
    parser.add_argument('-l','--link', help='僅顯示答案連結',
                        action='store_true')
    parser.add_argument('-c', '--color', help='啟用彩色輸出',
                        action='store_true')
    parser.add_argument('-n','--num-answers', help='傳回的答案數量',
                        default=1, type=int)
    parser.add_argument('-C','--clear-cache', help='清除快取',
                        action='store_true')
    parser.add_argument('-v','--version',
                        help='顯示 howdoi 的當前版本',
                        action='store_true')
    return parser

argparse 程式碼解密:

  1. argparse.ArgumentParser() 用於建立一個解析器物件。
  2. add_argument() 方法用於定義命令列引數和選項。
  3. action='store_true' 表示該選項是一個旗標,如果出現在命令列中,則在解析器的字典中儲存為 True
  4. 解析器將解析命令列並建立一個字典,該字典將每個引數對映到一個值。

docopt

docopt 的核心哲學是檔案應該是美觀且易於理解的。它提供了一個主要命令 docopt.docopt(),以及一些為高階使用者提供的便利函式和類別。docopt.docopt() 函式接受開發者編寫的 POSIX 風格的使用說明,並使用它們來解釋使用者的命令列引數,然後傳回一個包含從命令列解析的所有引數和選項的字典。它還適當地處理 --help--version 選項。

docopt 使用範例

#!/usr/bin/env python3
"""向你打招呼。

用法:
hello <name>... [options]
hello -h | --help | --version

選項:
-c, --capitalize 是否將名字大寫
-n REPS, --num_repetitions=REPS 重複次數 [預設:1]
"""
__version__ = "1.0.0"  # 為了 --version 所需

def hello(name, repetitions=1):
    for rep in range(repetitions):
        print('Hello {}'.format(name))

if __name__ == "__main__":
    from docopt import docopt
    arguments = docopt(__doc__, version=__version__)
    if arguments['<name>']:
        name = arguments['<name>'][0]
        repetitions = int(arguments['--num_repetitions'])
        hello(name, repetitions)

docopt 程式碼解密:

  1. 使用 """ """ 檔案字串定義了程式的使用說明和選項說明。
  2. docopt(__doc__, version=__version__) 解析命令列引數並傳回一個字典。
  3. 根據解析結果,呼叫 hello() 函式並傳遞相應的引數。

命令列應用程式開發工具比較與實務應用

在開發命令列應用程式時,開發者有多種工具可供選擇,包括 docopt、Plac、Click 和 Clint 等。這些工具各具特色,能夠簡化命令列引數的解析和處理流程,提升開發效率。本文將探討這些工具的特點、用法及實際應用場景。

Docopt:根據檔案字串的命令列引數解析

Docopt 是一種創新的命令列引數解析工具,它利用函式的檔案字串(docstring)來定義命令列介面。Docopt 能夠根據檔案字串中的特定格式解析命令列引數,並將其轉換為 Python 物件。

程式碼範例:使用 Docopt 解析命令列引數

arguments = docopt(__doc__, version=__version__)
name = ' '.join(arguments['<name>'])
repetitions = arguments['--num_repetitions']
if arguments['--capitalize']:
    name = name.upper()
hello(name, repetitions=repetitions)

內容解密:

  1. docopt(__doc__, version=__version__):使用檔案字串和版本資訊初始化 Docopt。
  2. arguments['<name>']arguments['--num_repetitions']:從解析結果中提取命令列引數。
  3. --capitalize 選項用於控制是否將名字大寫。

Plac:根據函式簽名的命令列引數解析

Plac 是一種輕量級的命令列引數解析工具,它透過分析目標函式的簽名來推斷命令列引數的結構。Plac 簡化了命令列應用程式的開發流程。

程式碼範例:使用 Plac 定義命令列介面

import plac

def hello(name, capitalize=False, repetitions=1):
    """向你打招呼。"""
    if capitalize:
        name = name.upper()
    for rep in range(repetitions):
        print('Hello {}'.format(name))

if __name__ == "__main__":
    plac.call(hello)

內容解密:

  1. plac.call(hello):呼叫 hello 函式並根據命令列引數執行。
  2. 函式簽名 def hello(name, capitalize=False, repetitions=1) 定義了命令列引數的結構。

Click:高度可組裝的命令列介面建立工具

Click 是一種功能強大的命令列介面建立工具,旨在簡化複雜命令列應用程式的開發。它提供了豐富的功能和高度的可組態性。

程式碼範例:使用 Click 建立命令列應用程式

import click

@click.command()
@click.argument('name', type=str)
@click.option('--capitalize', is_flag=True)
@click.option('--repetitions', default=1, help="重複問候的次數。")
def hello(name, capitalize, repetitions):
    """向你打招呼,可選擇是否大寫名字和重複次數。"""
    if capitalize:
        name = name.upper()
    for rep in range(repetitions):
        print('Hello {}'.format(name))

if __name__ == '__main__':
    hello()

內容解密:

  1. @click.command()@click.argument()@click.option() 裝飾器用於定義命令列介面。
  2. is_flag=True 表示 --capitalize 是一個標誌選項。
  3. default=1--repetitions 選項設定了預設值。

Clint:豐富的命令列介面工具集

Clint 提供了一系列用於增強命令列介面的工具,包括彩色輸出、縮排和進度條等功能,使命令列應用程式更加友好和易用。

程式碼範例:使用 Clint 實作彩色輸出和縮排

from clint.arguments import Args
from clint.textui import colored, indent, puts

def hello(name, capitalize, repetitions):
    if capitalize:
        name = name.upper()
    with indent(5, quote=colored.magenta(' ~*~', bold=True)):
        for i in range(repetitions):
            greeting = 'Hello {}'.format(colored.green(name))
            puts(greeting)

if __name__ == '__main__':
    args = Args()
    # 處理幫助訊息和其他命令列引數
    name = " ".join(args.grouped['_'].all)
    capitalize = args.any_contain('-c')
    repetitions = int(args.value_after('--reps') or 1)
    hello(name, capitalize=capitalize, repetitions=repetitions)

內容解密:

  1. indent(5, quote=colored.magenta(' ~*~', bold=True)):設定縮排和引導符號。
  2. colored.green(name)colored.magenta(' ~*~', bold=True):實作彩色輸出。
  3. puts(greeting):輸出問候訊息並處理縮排和引導符號。

命令列介面框架與圖形使用者介面開發

在開發命令列介面(CLI)應用程式時,Python 提供了多種框架和函式庫來簡化開發流程。其中,cliff 是一個強大的框架,用於建立具有多層級命令結構的 CLI 程式,如 svngit。另一方面,在圖形使用者介面(GUI)開發方面,Python 提供了多種工具包和框架,以簡化視窗元件的建立和管理。

使用 cliff 框架建立 CLI 應用程式

cliff 是一個用於建立 CLI 程式的框架,它提供了抽象基礎類別來組織功能。開發者需要實作 cliff.command.Command 類別以定義子命令,並使用 cliff.commandmanager.CommandManager 來管理這些命令。

建立一個簡單的 CLI 應用程式

以下是一個使用 cliff 的簡單範例:

import sys
from argparse import ArgumentParser
from pkg_resources import get_distribution
from cliff.app import App
from cliff.command import Command
from cliff.commandmanager import CommandManager

__version__ = get_distribution('HelloCliff').version

class Hello(Command):
    """對某人說你好。"""
    
    def get_parser(self, prog_name):
        parser = ArgumentParser(description="Hello 命令", prog=prog_name)
        parser.add_argument('--num', type=int, default=1, help='重複次數')
        parser.add_argument('--capitalize', action='store_true')
        parser.add_argument('name', help='人名')
        return parser
    
    def take_action(self, parsed_args):
        if parsed_args.capitalize:
            name = parsed_args.name.upper()
        else:
            name = parsed_args.name
        for i in range(parsed_args.num):
            self.app.stdout.write("Hello from cliff, {}.\n".format(name))

class MyApp(App):
    def __init__(self):
        super(MyApp, self).__init__(
            description='Cliff 中的最小應用程式',
            version=__version__,
            command_manager=CommandManager('named_in_setup_py'),
        )

def main(argv=sys.argv[1:]):
    myapp = MyApp()
    return myapp.run(argv)

內容解密:

  1. 匯入必要的模組:首先,範例程式碼匯入了必要的模組,包括 argparse 用於解析命令列引數,cliff.appcliff.commandcliff.commandmanager 用於建立 CLI 應用程式。
  2. 定義 Hello 命令Hello 類別繼承自 cliff.command.Command,並實作了 get_parsertake_action 方法。get_parser 方法定義了命令的引數,而 take_action 方法則定義了當命令被呼叫時執行的動作。
  3. 定義主應用程式類別 MyAppMyApp 類別繼承自 cliff.app.App,負責設定應用程式的全域屬性,如日誌、I/O 流等。
  4. 主函式main 函式建立了 MyApp 的例項並執行它。

圖形使用者介面(GUI)開發

在 GUI 開發方面,Python 提供了多種工具包和框架,如 Tkinter、Kivy、PyQt 和 wxPython 等。這些工具包提供了豐富的視窗元件,如按鈕、捲軸和文字方塊等,以簡化 GUI 的開發。

常用的 GUI 工具包

底層函式庫(語言)Python 函式庫授權條款使用理由
Tk (Tcl)tkinterPython 軟體基金會授權條款所有相依性已包含在 Python 中,提供標準的 UI 元件。
SDL2 (C)KivyMIT 或 LGPL3(1.7.2 之前)可用於建立 Android 應用程式,支援多點觸控,使用 GPU 最佳化。
Qt (C++)PyQtGNU 通用公共授權條款(GPL)或商業授權提供跨平台的一致性外觀和感覺,已被許多應用程式和函式庫使用。
GTK (C)PyGObjectGNU 較寬通用公共授權條款(LGPL)為 GTK+ 3 提供 Python 繫結,應對已熟悉 GNOME 桌面系統開發的人來說很熟悉。

內容解密:

  1. 多樣化的 GUI 工具包:Python 提供了多種 GUI 工具包,以滿足不同的開發需求和偏好。
  2. 選擇合適的工具包:開發者可以根據專案需求、目標平台和個人偏好選擇合適的 GUI 工具包。
  3. 跨平台支援:許多 GUI 工具包提供了跨平台支援,使得開發者能夠在多個作業系統上佈署應用程式。

總之,Python 為 CLI 和 GUI 應用程式的開發提供了豐富的框架和工具包。開發者可以根據專案需求選擇合適的工具,以簡化開發流程並提高生產力。