掌握 Python 的 argparse 模組:打造更好的命令列介面

Python是一種強大的程式語言,允許開發人員創建各種應用程式,從基本腳本到大型軟體系統。其中最常見的程式設計任務之一是創建命令列介面(CLIs),這使得用戶可以通過終端或命令行與程式互動。CLIs對於腳本編寫、自動化以及圖形使用者介面不切實際的情況下是必不可少的。

處理命令列參數是設計CLIs的一個重要部分。這些參數允許用戶通過在程式運行時提供輸入參數來影響程式的行為。如果沒有評估這些因素的能力,程式將更少靈活,並且更難調整以滿足特定任務的需求。

Python提供了幾個模組來解析命令列參數,但argparse模組因其簡單性和全面性而脫穎而出。argparse模組使得開發功能性命令列介面變得簡單。它自動處理參數解析,顯示有用的說明,並在用戶提供不正確資訊時提供錯誤提示。

在本教程中,我們將介紹如何使用Python argparse套件。我們將從Python的命令列介面概述及解析命令列輸入的重要性開始,然後討論argparse模組及其優點。

Python中的命令列介面概述

命令行界面是純粹依靠文字命令運行的程序。用戶通過終端或命令行輸入命令,這些命令通常包括可以改變程序行為的參數和選項。CLI很有用,因為它們易於自動化並與其他技術集成。

在Python中,通過開發接受命令行輸入的腳本來創建CLI。這些輸入通常以一個參數列表的形式呈現,腳本可以訪問和解釋這些參數。對於基本程序,通過sys.argv列表手動處理這些參數可能就足夠了。然而,當程序的復雜性增加時,手動處理參數會變得低效和容易出錯。

解析命令行參數的重要性

解析命令行參數是必要的,原因有很多:

  • 靈活性:通過接受參數,程序可以執行多個任務或對不同數據集進行操作,而無需更改代碼。用戶可以指定要處理的文件、配置設置,以及選擇操作模式。
  • 用戶友好性正確的參數解析使程序能夠顯示有用的消息,指導用戶如何使用程序,並優雅地處理故障。
  • 可維護性:使用專用的解析模組,如 argparse,可以讓您的程式碼更清晰、更容易維護。它將用於解析參數的邏輯與程式的主要操作分開。

介紹argparse模組及其優點

argparse 模組是 Python 標準庫的一部分。因此,您可以在不安裝任何其他套件的情況下使用它。它提供了一個直觀且一致的介面,用於解析命令列輸入。使用 argparse 的一些優點包括:

  • 自動幫助文件生成:根據程式碼的參數生成幫助和使用訊息。
  • 錯誤處理:當用戶輸入無效參數時,顯示有用的錯誤訊息。
  • 類型轉換:它可以自動將參數字符串轉換為適當的資料類型。
  • 它支援必要的位置參數和可選參數,並具有簡單的設置。
  • 默認值:允許您為未提供的參數提供默認值。

argparse 讓開發人員專注於他們程序的主要功能,同時依賴於一個強大的基礎來管理命令行輸入。

設置 argparse 和基本用法

現在我們已經談過解析命令行參數的重要性以及使用 argparse 的優勢,讓我們看看如何在 Python 腳本中設置並使用它。

安裝並導入 argparse

無需單獨安裝任何東西,因為 argparse 是 Python 標準庫的一部分。您可以在腳本的開頭直接導入它。

import argparse

這行將 argparse 模塊加載到您的腳本中,使您能夠使用其功能來解析命令行參數。

創建一個簡單的參數解析器

利用 argparse 的第一步是生成一個解析器對象。此對象將存儲有關您的程序接受的參數的信息並解析命令行輸入。

parser = argparse.ArgumentParser(description='Process some integers.')

在這個例子中,我們創建一個 ArgumentParser() 對象並描述程序。當用戶選擇幫助選項(-h 或 –help)時,將顯示此描述。

添加位置參數和可選參數

現在我們已經開發了解析器,我們可以指定程序將接受的參數。

添加位置參數

位置參數是必不可少的,必須按照精確的順序呈現。例如,考慮一個將兩個數字相加的腳本。我們可以為這兩個數字定義兩個位置參數:

parser.add_argument('num1', type=int, help='The first number to add.') parser.add_argument('num2', type=int, help='The second number to add.')

在這段程式碼中,num1num2 代表位置參數。

type=int 表示這些參數應該被轉換為整數。help 參數指定一個描述,將顯示在幫助訊息中。

添加可選參數

可選參數並非必需,通常提供額外選項或更改程式行為。它們通常以一個或兩個破折號作為前綴。我們將添加一個可選參數來啟用冗長輸出:

parser.add_argument('-v', '--verbose', action='store_true', help='Increase output verbosity.')

在這裡:

  • 簡短選項是 -v(例如,-v)。--verbose 是一個冗長選項。
  • action='store_true' 表示如果選擇了該選項,則 verbose 屬性將設置為 True;否則為 False
  • help 參數為幫助訊息指定一個描述。

解析參數並訪問它們的值

在指定所有參數後,我們需要解析命令列輸入。使用 .parse_args() 方法來實現這一點。

args = parser.parse_args()

解析後的參數現在存儲在 args 變數中作為屬性。我們可以使用點表示法訪問它們。

result = args.num1 + args.num2 print('The sum of {} and {} is {}'.format(args.num1, args.num2, result)) if args.verbose: print('Verbose mode is enabled.')

將所有內容放在一起,這裡是一個完整的腳本,可以將兩個數字相加,並包括一個可選的冗長模式:

import argparse parser = argparse.ArgumentParser(description='Add two integers.') parser.add_argument('num1', type=int, help='The first number to add.') parser.add_argument('num2', type=int, help='The second number to add.') parser.add_argument('-v', '--verbose', action='store_true', help='Increase output verbosity.') args = parser.parse_args() result = args.num1 + args.num2 print('The sum of {} and {} is {}'.format(args.num1, args.num2, result)) if args.verbose: print('Calculation completed successfully.')

您可以在命令列運行這個腳本並提供所需的位置參數:

python add_numbers.py 3 5 The sum of 3 and 5 is 8

如果包含-v--verbose选项,脚本将打印额外的详细信息:

python add_numbers.py 3 5 --verbose The sum of 3 and 5 is 8 Calculation completed successfully.

如果用户使用-h--help选项运行脚本,argparse将显示自动生成的帮助信息:

python add_numbers.py -h usage: add_numbers.py [-h] [-v] num1 num2 Add two integers. positional arguments: num1 The first number to add. num2 The second number to add. optional arguments: -h, --help show this help message and exit -v, --verbose Increase output verbosity.

此功能使您的程序更加用户友好,提供清晰的使用说明。

高级参数处理

在开发Python命令行程序时,您可能会遇到需要更复杂参数解析的情况。Python的argparse模块包含多项功能来满足这些复杂需求,让您开发灵活、用户友好的界面。

使用nargs接受多个参数

有时候您的应用程序需要接受同一个参数的多个值。例如,假设您希望创建一个一次处理多个文件的脚本。在argparse中的nargs参数允许您指定应读取多少个命令行参数。

以下是如何使用nargs接受多个文件名:

import argparse parser = argparse.ArgumentParser(description='Process multiple files.') parser.add_argument('filenames', nargs='+', help='List of files to process.') args = parser.parse_args() for filename in args.filenames: print(f'Processing file: {filename}') # 在此处添加您的文件处理代码

在这种情况下,nargs='+'指示解析器期望在文件名中提供一个或多个参数。用户可以提供任意数量的文件名,并且它们将保存在名为args.filenames的列表中。

如果您想要接受一定数量的参数,将nargs设置为该数字。例如,nargs=2要求恰好两个参数。

實現限制參數值的選項

有時,您希望將參數限制在指定範圍的有效值內。這可以確保用戶提供有效的輸入,從而避免錯誤或意外操作。選項參數允許您為參數指定可接受的值。

考慮一個腳本,根據用戶選擇的模式執行多個活動。

import argparse parser = argparse.ArgumentParser(description='Perform actions in different modes.') parser.add_argument('--mode', choices=['backup', 'restore', 'delete'], required=True, help='Mode of operation.') args = parser.parse_args() if args.mode == 'backup': print('Backing up data...') # 備份代碼 elif args.mode == 'restore': print('Restoring data...') # 恢復代碼 elif args.mode == 'delete': print('Deleting data...') # 刪除代碼

在這個腳本中,--mode參數必須是選項之一。如果用戶輸入的值不在列表中,argparse將返回錯誤消息。

處理布爾標誌和切換

布爾標誌是選項,可以在應用程序中啟用或禁用特定功能。它們通常是在命令中包含標誌而不使用值來定義的。您可以使用argparse中的action參數來處理這些標誌。

例如,讓我們在腳本中包含一個調試模式:

import argparse parser = argparse.ArgumentParser(description='A script with debug mode.') parser.add_argument('--debug', action='store_true', help='Enable debug output.') args = parser.parse_args() if args.debug: print('Debug mode is enabled.') # 這裡是額外的調試信息 else: print('Debug mode is disabled.')

通過使用action='store_true'--debug標誌將在存在時將args.debug設置為True,否則設置為False

設置默認值和必要參數

可選參數通常包含合理的默認值。這表示如果用戶未指定該參數,應用程序將使用默認值。default 參數允許您指定默認值。

以下是一個例子:

import argparse parser = argparse.ArgumentParser(description='Adjust program settings.') parser.add_argument('--timeout', type=int, default=30, help='Timeout in seconds.') args = parser.parse_args() print(f'Timeout is set to {args.timeout} seconds.')

在這種情況下,如果用戶未指定 --timeout,默認值為30秒。

要將可選參數設置為必需,請使用 set required=True

import argparse parser = argparse.ArgumentParser(description='Send a message.') parser.add_argument('--recipient', required=True, help='Recipient of the message.') args = parser.parse_args() print(f'Sending message to {args.recipient}.')

現在腳本將要求 --recipient 參數。

自定義幫助和錯誤消息

向用戶提供清晰和有用的消息是開發有效的命令行程序的重要組成部分。Python 的 argparse 模塊會自動生成幫助消息,但您可以修改這些消息以更好地滿足您的需求。

生成自動幫助消息

默認情況下,argparse 會生成幫助消息,可以使用 -h--help 選項訪問該消息。該消息包含程序的用法、描述以及關於每個參數的信息。

例如:

import argparse parser = argparse.ArgumentParser(description='Calculate factorial of a number.') parser.add_argument('number', type=int, help='The number to calculate the factorial for.') args = parser.parse_args()

當用戶運行腳本時帶有 -h,他們將看到:

usage: script.py [-h] number Calculate factorial of a number. positional arguments: number The number to calculate the factorial for. optional arguments: -h, --help show this help message and exit

該自動幫助消息提供有用信息,而無需進行任何額外的努力。

自定義幫助描述和用法消息

儘管默認幫助消息很有用,但您可能希望修改它們以提供額外信息或符合特定結構。您可以在 ArgumentParser 中更改描述、尾注和用法文本。

例如,要包括一个结语并个性化使用说明:

import argparse parser = argparse.ArgumentParser( description='Convert temperatures between Celsius and Fahrenheit.', epilog='Enjoy using the temperature converter!', usage='%(prog)s [options] temperature') parser.add_argument('temperature', type=float, help='Temperature value to convert.') parser.add_argument('--to-fahrenheit', action='store_true', help='Convert Celsius to Fahrenheit.') parser.add_argument('--to-celsius', action='store_true', help='Convert Fahrenheit to Celsius.') args = parser.parse_args()

现在,当用户检查帮助消息时,它将包括定制的描述、用法和结语:

python file.py --help usage: p.py [options] temperature Convert temperatures between Celsius and Fahrenheit. positional arguments: temperature Temperature value to convert. options: -h, --help show this help message and exit --to-fahrenheit Convert Celsius to Fahrenheit. --to-celsius Convert Fahrenheit to Celsius.

–to-fahrenheit 将摄氏度转换为华氏度。

–to-celsius 将华氏度转换为摄氏度。

管理错误处理和用户反馈

import argparse import sys class CustomArgumentParser(argparse.ArgumentParser): def error(self, message): print(f'Error: {message}') self.print_help() sys.exit(2) parser = CustomArgumentParser(description='Divide two numbers.') parser.add_argument('numerator', type=float, help='The numerator.') parser.add_argument('denominator', type=float, help='The denominator.') args = parser.parse_args() if args.denominator == 0: parser.error('Denominator cannot be zero.') result = args.numerator / args.denominator print(f'Result: {result}')

如果用户输入无效参数,argparse将显示错误消息并退出程序。您可以修改此行为以提供更有用的反馈或以不同方式处理故障。

Python file.py 6 0 Error: Denominator cannot be zero. usage: file.py [-h] numerator denominator Divide two numbers. positional arguments: numerator The numerator. denominator The denominator. options: -h, --help show this help message and exit

一种方法是在 ArgumentParser的子类中覆盖错误方法:

import argparse import os parser = argparse.ArgumentParser(description='Read a file and display its contents.') parser.add_argument('filepath', help='Path to the file.') args = parser.parse_args() if not os.path.exists(args.filepath): parser.error(f"The file {args.filepath} does not exist.") with open(args.filepath, 'r') as file: contents = file.read() print(contents)

如果用户在此脚本中尝试除以零,应用程序将显示错误警告和帮助文本,指导用户提供有效数据。

python app..py file usage: p.py [-h] filepath app.py: error: The file file does not exist.

您还可以在脚本中包含自定义错误处理。例如,管理无效文件路径:

執行具有無效路徑的腳本將顯示以下錯誤:

真實世界的示例和用例

了解如何在真實世界的情況下使用argparse模塊將使其功能更清晰。讓我們看一些在真實應用中如何使用argparse的例子。

構建命令行計算器

import argparse parser = argparse.ArgumentParser(description='Simple command-line calculator.') parser.add_argument('num1', type=float, help='First number.') parser.add_argument('operator', choices=['+', '-', '*', '/'], help='Operation to perform.') parser.add_argument('num2', type=float, help='Second number.') args = parser.parse_args() if args.operator == '+': result = args.num1 + args.num2 elif args.operator == '-': result = args.num1 - args.num2 elif args.operator == '*': result = args.num1 * args.num2 elif args.operator == '/': if args.num2 == 0: print('Error: Division by zero is not allowed.') exit(1) result = args.num1 / args.num2 print(f'The result is: {result}')

假設您需要開發一個可以從命令行執行基本算術操作的簡單計算器。這個計算器應該接受兩個數字和一個運算符來執行所請求的計算。

python calculator.py 10 + 5 The result is: 15.0

這是如何處理這個任務:

在這個腳本中,使用argparse模塊來定義三個位置參數:兩個數字和一個運算符。 choices參數將運算符限制為有效的算術符號。當用戶運行腳本時,他們可以執行這些計算:

這個基本計算器展示了命令行選項如何增強程序的靈活性和互動性。

創建具有多個選項的文件處理腳本

import argparse parser = argparse.ArgumentParser(description='Process text files.') parser.add_argument('input_file', help='Path to the input file.') parser.add_argument('-o', '--output', help='Path to the output file.') parser.add_argument('-m', '--mode', choices=['uppercase', 'lowercase'], default='uppercase', help='Processing mode.') parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output.') args = parser.parse_args() 假設您需要一個處理文本文件並提供選擇的腳本,例如指定輸出文件、選擇處理模式以及啟用冗長輸出。 with open(args.input_file, 'r') as file: content = file.read() if args.verbose: print(f'Reading from {args.input_file}') 這是您如何設置的示例: if args.mode == 'uppercase': processed_content = content.upper() else: processed_content = content.lower() if args.verbose: print('Processing content') # 讀取輸入文件 if args.output: with open(args.output, 'w') as file: file.write(processed_content) if args.verbose: print(f'Writing output to {args.output}') else: print(processed_content)

# 處理內容

python text_processor.py input.txt -o output.txt --mode lowercase -v Reading from input.txt Processing content Writing output to output.txt

# 寫入輸出文件或打印到控制台

這個腳本接受一個輸入文件,並具有選項用於輸出文件、處理模式和冗長輸出。用戶可以修改腳本的行為方式,而不需要改變代碼。

開發帶有子命令的CLI工具

import argparse parser = argparse.ArgumentParser(description='Manage tasks.') subparsers = parser.add_subparsers(dest='command', required=True) 在更複雜的應用程序中,可能需要子命令,類似於使用命令(例如git commit和git push)的git的方式。 argparse 模塊提供了子解析器來實現這一目的。 parser_add = subparsers.add_parser('add', help='Add a new task.') parser_add.add_argument('name', help='Name of the task.') parser_add.add_argument('-p', '--priority', type=int, choices=range(1, 6), default=3, help='Priority of the task.') 下面是如何製作帶有子命令的CLI工具: parser_list = subparsers.add_parser('list', help='List all tasks.') parser_list.add_argument('-a', '--all', action='store_true', help='List all tasks, including completed ones.') # 子命令 'add' parser_complete = subparsers.add_parser('complete', help='Mark a task as completed.') parser_complete.add_argument('task_id', type=int, help='ID of the task to complete.') args = parser.parse_args() if args.command == 'add': print(f"Adding task '{args.name}' with priority {args.priority}") # 子命令 'list' elif args.command == 'list': print('Listing tasks') if args.all: print('Including completed tasks') # 子命令 'complete' elif args.command == 'complete': print(f'Marking task {args.task_id} as completed') # 添加任務的代碼

# 列出任務的代碼

# 完成任務的代碼

python task_manager.py add "Write report" -p 2 Adding task 'Write report' with priority 2

在這個例子中,腳本有三個子命令:addlistcomplete。每個子命令都有它自己的參數。當用戶運行腳本時,他們輸入子命令和任何其他參數。

python task_manager.py list Listing tasks

例如:

python task_manager.py complete 3 Marking task 3 as completed

列出任務

將任務標記為已完成:

subparsers 讓您能夠創建複雜的命令行工具,它們組織良好並易於擴展,使您能夠構建可以在單個界面中執行多項任務的應用程序。

Python argparse 最佳實踐和技巧

開發命令行程序不僅僅是寫出能運行的代碼,還包括編寫乾淨、易於維護和用戶友好的代碼。

在使用argparse模塊時,以下是一些最佳實踐。

為提高代碼的可讀性和可維護性組織代碼

當您的腳本變得更加複雜時,保持代碼的組織性對於更好地理解和維護至關重要。一種實現這一目標的方法是使用函數和類來組織代碼的不同部分。

將程序拆分為更小、可重用的片段使其更易於管理並消除代碼重複。

例如,在任務管理腳本中,您可以為添加任務、列出任務和完成任務定義不同的函數。這種劃分使您可以一次專注於邏輯的一個方面,使您的代碼更清晰。

另一種有效的技術是將參數解析邏輯與其餘代碼分開。將所有參數定義和解析放在腳本的開頭,或在專用函數中,使其他人更容易理解您的程序如何處理輸入。

使用適當的變量名稱也可以提高可讀性。選擇反映其用途的變量名稱,這樣任何查看您代碼的人都可以理解正在發生什麼。包括評註和docstrings來解釋您的函數的功能以及任何關鍵細節,可以幫助提高理解。

測試和調試命令行應用程式

測試應用程式對確保其正常運作和及早檢測問題至關重要。使用 Python 測試框架(例如unittestpytest)編寫單元測試是測試代碼的一個很好的方法。這些測試允許您模擬各種輸入,確保您的函數正常運作。

例如,您可以通過模擬命令行輸入而不是從命令行運行腳本來測試多種情況。這種策略可以確保您的參數解析按預期工作,應用程式正確處理各種情況。

優雅處理異常情況也是至關重要的。使用try-except塊,您可以捕獲錯誤並向用戶提供有用的消息。這使您的應用程式更穩定和用戶友好。

同時,在腳本中加入調試標誌也很重要。該標誌可以啟用額外的輸出,讓您在發生問題時跟踪程序的執行。有這個選項使得在開發和維護過程中更容易診斷問題。

比較 argparse 與其他參數解析庫

雖然argparse是 Python 標準庫中有價值的工具,但還有其他可用的庫提供另類方法來解析命令行參數。了解這些選項將幫助您為項目選擇合適的工具。

一個這樣的庫是Click。Click是一個用於通過裝飾器創建命令行界面的第三方套件。它具有更直觀的語法,非常適合複雜的應用程序。例如,您可以使用Python裝飾器來創建命令和選項,使您的代碼更緊湊和易於理解。

Docopt是另一個選項,它允許您使用程序的docstring來定義您的命令行界面。當在docstring中包含使用說明時,Docopt會自動解析幫助消息並構建參數解析器。這種方法優雅且適用於需要更易讀規範的簡單腳本。

在選擇要使用的庫時,請考慮您項目的需求。如果您希望消除外部依賴並且需要一個能處理大多數情況的工具,argparse是一個很好的解決方案。如果您想要更直觀的語法並且正在開發一個複雜應用程序,Click可能更適合。對於具有簡單界面的小型程序,Docopt是一個不錯的選擇。

結論

在本文中,我們已經瞭解了如何使用Python的argparse模組來開發Python中的命令行程序。通過實際示例,我們學會了如何創建接收用戶輸入並完成相關任務的實用腳本。

Source:
https://www.datacamp.com/tutorial/python-argparse