Python / argparse === ###### tags: `Python` ###### tags: `Python`, `ArgumentParser`, `argument_parser`, `add_argument`, `parse_args`, `store`, `store_true`, `store_false`, `store_const`, `append`, `append_const`, `count`, `version` <br> [TOC] <br> - [Argparse with two values for one argument](https://stackoverflow.com/questions/34988908/) ```python! parser.add_argument( '-c', '--compare', nargs=2, metavar=('newfile', 'oldfile'), help='Compares previous run results in oldfile with current run results in newfile.', ) args = parser.parse_args() newfile, oldfile = args.compare ``` ![](https://i.imgur.com/WomXSxL.png) - [What is the right way to treat Python argparse.Namespace() as a dictionary?](https://stackoverflow.com/questions/16878315/) <br> ## 官方教學 > [[官網] argparse --- 命令行选项、参数和子命令解析器](https://docs.python.org/zh-tw/3/library/argparse.html#) ### nargs > https://docs.python.org/zh-cn/3.7/library/argparse.html#nargs > #不定長度 不定個數 - `nargs='?'` None 或 單一值 - `nargs='+'` 清單 (type=list) - ### case 1 ``` from argparse import ArgumentParser parser = ArgumentParser() parser.description = 'Check the FastQC report, and run the Trimmomatic process if necessary.' parser.add_argument('read1', help='input the R1 of paired-end FASTQ files, or a single-end FASTQ file') parser.add_argument('read2', nargs='?', help='input the R2 of paired-end FASTQ files') args = parser.parse_args() ``` 執行方式 ``` $ python qc_runner.py NA24631_1.fastq.gz $ python qc_runner.py NA24631_1.fastq.gz NA24631_2.fastq.gz ``` <br> ## 教學 - ### [Python 超好用標準函式庫 argparse](https://dboyliao.medium.com/4eab2e9dcc69) ```python= # example.py from argparse import ArgumentParser parser1 = ArgumentParser() parser2 = ArgumentParser(prog="my_example") parser3 = ArgumentParser(usage="usage") parser4 = ArgumentParser(description="a simple demo of argparse") parser5 = ArgumentParser(epilog="see the doc: https://docs.python.org/3/library/argparse.html") parser1.print_help() # usage: example.py [-h] # # optional arguments: # -h, --help show this help message and exit parser2.print_help() # usage: my_example [-h] # # optional arguments: # -h, --help show this help message and exit parser3.print_help() # usage: usage # # optional arguments: # -h, --help show this help message and exit parser4.print_help() # usage: example.py [-h] # # a simple demo of argparse # # optional arguments: # -h, --help show this help message and exit parser5.print_help() # usage: example.py [-h] # # optional arguments: # -h, --help show this help message and exit # # see the doc: https://docs.python.org/3/library/argparse.html ``` - ### [Python argparse 教學:比 sys.argv 更好用,讓命令列引數整潔又有序](https://haosquare.com/python-argparse/) <br> ## code snippet ### language: str ```python= parser.add_argument( '-l', '--lang', type=str, choices=['en', 'tw'], default=os.getenv('LANG', 'en')[:2], # LANG=en_US.UTF-8 -> LANG=en help='The language to use: "en" for English, "tw" for Traditional Chinese') ``` ### process pdf: flag ```python= # Convert a value in str to bool def str2bool(s: str) -> bool: if s and s.strip().lower() in ['true', 't', 'yes', 'y', '1']: return True return False parser.add_argument( '-p', '--pdf', action='store_true', default=str2bool(os.getenv('PROCESS_PDF', 'False')), help='Flag to process PDFs and convert to images') ``` ### choices (限定選項) ``` parser.add_argument( '-n', '--output_dir_name', type=str, required=True, choices=['output-text', 'output-640x960', 'output-1920x1080'], help='Specify the dir name for output (choose from "output-text", "output-640x960", "output-1920x1080")' ) ``` <br> ## 討論 ### action='store_true' 是什麼意思? - gpt-4o-2024-08-06 `action='store_true'` 是 `argparse` 模組中用來定義布林(Boolean)旗標參數的選項。當你在命令列中提供這個參數時,該參數的值會被設置為 `True`,如果沒有提供,則預設為 `False`。 這樣的參數通常用於開啟或關閉某個功能,類似於開關。 ### 具體說明: - **如果使用者在命令列輸入了 `--pdf`**,則 `args.pdf` 會被設為 `True`。 - **如果使用者沒有輸入 `--pdf`**,則 `args.pdf` 會被設為 `False`。 ### 範例: 假設有以下程式碼: ```python= parser = argparse.ArgumentParser(description="Process some PDFs.") parser.add_argument('--pdf', action='store_true', help="Enable PDF processing") args = parser.parse_args() if args.pdf: print("PDF processing enabled") else: print("PDF processing not enabled") ``` 在命令列中: 1. 執行 `python script.py --pdf` 會印出: ``` PDF processing enabled ``` 2. 執行 `python script.py`(不帶 `--pdf` 參數)會印出: ``` PDF processing not enabled ``` ### 結論: `action='store_true'` 的作用是當你在命令列中輸入該選項(如 `--pdf`),它的值會自動變成 `True`;若未輸入,則保持為 `False`。 <br> ### `parser.add_argument` 的 `action` 參數,要如何使用? - gpt-4o-2024-08-06 在 Python 的 `argparse` 模組中,`action` 參數用來決定當命令行解析器遇到某個選項時應該執行什麼操作。`action` 有多種內建的選項,適用於不同情況,例如設定布林值、累積計數、儲存常量值等。 ### `action` 參數的常見使用方法: 1. **`store`**(預設值):將選項後面的值存儲在對應的變數中。 - 預設情況下,`argparse` 的行為就是 `store`,即將參數的值儲存到對應變數中。 ```python parser.add_argument('--foo', action='store') # 默認行為 ``` 2. **`store_true` 和 `store_false`**:當選項被指定時,將布爾值 `True` 或 `False` 儲存到變數中。 - 常用於處理布爾開關參數,例如開啟或關閉某個功能。 ```python parser.add_argument('--verbose', action='store_true', help='enable verbose output') parser.add_argument('--no-verbose', action='store_false', help='disable verbose output') ``` 當使用 `--verbose` 時,`verbose` 變數會設為 `True`,不指定時為 `False`。同理,`--no-verbose` 會設為 `False`。 3. **`store_const`**:將指定的常量值存儲在變數中。 - 用於當你希望參數出現時,變數的值是一個特定的常量,而不是來自命令行的輸入。 ```python parser.add_argument('--foo', action='store_const', const=42, help='set foo to 42') ``` 在這種情況下,如果指定了 `--foo`,則 `foo` 變數的值會被設置為 `42`。 4. **`append`**:將選項後面的值追加到一個列表中。 - 如果你希望同一個選項能夠多次出現並存儲多個值,可以使用 `append`。 ```python parser.add_argument('--foo', action='append', help='append items to the list') ``` 使用方法如 `--foo 1 --foo 2 --foo 3`,最後 `foo` 變數會變成 `[1, 2, 3]`。 5. **`append_const`**:將常量追加到一個列表中。 - 和 `store_const` 類似,但會將常量值追加到一個列表中。 ```python parser.add_argument('--add-foo', action='append_const', const='foo', help='append "foo" to the list') parser.add_argument('--add-bar', action='append_const', const='bar', help='append "bar" to the list') ``` 使用 `--add-foo --add-bar` 時,列表會變成 `['foo', 'bar']`。 6. **`count`**:計數指定參數的出現次數,並將其存儲為整數。 - 常用於像 `-v` 這樣的選項,用來增加詳細程度,出現次數越多,詳情級別越高。 ```python parser.add_argument('-v', '--verbose', action='count', help='increase verbosity level') ``` 使用 `-v -vv`,`verbose` 變數會根據 `-v` 的次數來增加數值。 7. **`help`** 和 **`version`**:內建的特殊 `action`,用於自動顯示幫助訊息或版本資訊。 ```python parser.add_argument('--version', action='version', version='%(prog)s 1.0') ``` 使用 `--version` 會輸出類似 `myprogram 1.0` 的訊息。 ### 範例 假設你想實現一個腳本,它有以下功能: 1. 如果使用 `--verbose`,將顯示更多詳細信息。 2. 可以通過 `--output` 指定輸出文件。 3. 可以用 `--append` 追加多個項目到列表中。 以下是相應的代碼: ```python= import argparse parser = argparse.ArgumentParser(description='Sample parser with action parameter.') # store_true 來處理布爾開關 parser.add_argument('--verbose', action='store_true', help='enable verbose output') # 指定文件輸出,默認行為是 'store' parser.add_argument('--output', action='store', help='specify output file') # append 將多次出現的選項加入到列表中 parser.add_argument('--append', action='append', help='append items to the list') args = parser.parse_args() if args.verbose: print("Verbose mode is on.") if args.output: print(f"Output will be written to {args.output}") if args.append: print(f"Items: {args.append}") ``` 這段代碼展示了如何使用 `action` 參數來處理不同的選項行為。 - ### `version='%(prog)s 1.0'`,`%(prog)s` 的 `s` 是什麼意思? 在 `argparse` 中,`%(prog)s` 是一個佔位符,它表示當前程序的名稱。這個佔位符會自動替換為當前腳本的名字,即執行該腳本時的程式名。 具體來說,`%(prog)s` 中的 `s` 是 Python 標準格式化字符串語法的一部分,用於將變量格式化為字符串。在這裡,它表示將 `prog` 的值(即程序名稱)格式化為一個字符串。 這個佔位符來自 `argparse.ArgumentParser` 中的 `prog` 屬性,它默認是執行腳本時使用的名稱。如果你沒有指定 `prog`,`argparse` 會自動使用腳本的名稱。 例如,如果你的腳本名為 `my_script.py`,並且你使用了這個參數: ``` parser.add_argument('--version', action='version', version='%(prog)s 1.0') ``` 執行 `python my_script.py --version` 時,會顯示: ``` my_script.py 1.0 ``` 這裡的 `my_script.py` 是自動替換的程序名稱,`%(prog)s` 就是相當於 `my_script.py`。 <br> ### Python argparse 使用 sub-commands(子命令)範例 - ### Question python 的 argparse.ArgumentParser 有 sub-program 的用法嗎? 就是 sub-program 有自己的參數 arg1, arg2, arg3 - ### gpt-4o-2024-08-06 是的,Python 的 `argparse` 模組支援 `sub-commands`(子命令),每個 `sub-command` 可以有自己的參數,像是 `arg1`、`arg2`、`arg3`。這是使用 `argparse.ArgumentParser` 和 `add_subparsers()` 方法來實現的。 以下是一個範例,展示如何定義主命令和子命令,每個子命令都有自己的參數: ```python= import argparse # 創建主解析器 parser = argparse.ArgumentParser(description="Main Program with Sub-commands") subparsers = parser.add_subparsers(dest='subcommand', help='Sub-commands help') # 定義第一個子命令 'sub1' parser_sub1 = subparsers.add_parser('sub1', help='Sub-program 1') parser_sub1.add_argument('--arg1', type=int, help='Argument 1 for sub1') # 定義第二個子命令 'sub2' parser_sub2 = subparsers.add_parser('sub2', help='Sub-program 2') parser_sub2.add_argument('--arg2', type=str, help='Argument 2 for sub2') # 定義第三個子命令 'sub3' parser_sub3 = subparsers.add_parser('sub3', help='Sub-program 3') parser_sub3.add_argument('--arg3', type=float, help='Argument 3 for sub3') # 解析參數 args = parser.parse_args() # 根據子命令執行不同的操作 if args.subcommand == 'sub1': print(f"Sub-program 1, arg1: {args.arg1}") elif args.subcommand == 'sub2': print(f"Sub-program 2, arg2: {args.arg2}") elif args.subcommand == 'sub3': print(f"Sub-program 3, arg3: {args.arg3}") else: parser.print_help() ``` ## 說明: - `add_subparsers()` 用於創建一個子命令的容器,並將子命令附加到主解析器中。 - 每個子命令都可以透過 `add_parser()` 方法創建,並且可以為每個子命令定義自己的參數。 - `subcommand` 是透過 `dest='subcommand'` 設定的,這會根據用戶輸入的子命令名稱來識別。 ## 執行範例: ```python= # 執行子命令 'sub1' 並提供 --arg1 參數 python script.py sub1 --arg1 123 # 執行子命令 'sub2' 並提供 --arg2 參數 python script.py sub2 --arg2 hello # 執行子命令 'sub3' 並提供 --arg3 參數 python script.py sub3 --arg3 3.14 ``` 這樣每個子命令都可以有自己的參數和邏輯,像是你所說的 `sub-program`。 <br> ### vars(...) 用途為何? - ### gpt-4o-2024-08-06 `vars()` 是一個內建函式,它會返回某個對象的屬性字典,該字典將屬性名稱對應到它們的值。在 `argparse` 的上下文中,`vars()` 通常被用來將解析後的參數(以 `Namespace` 對象的形式)轉換成一個字典,方便進行檢查或處理。 在你的程式中,使用 `vars(args)` 的主要目的是將 `args`(解析命令列參數後的 `Namespace` 對象)轉換為一個字典。這樣,你可以檢查所有參數的值,看看是否有任何參數被提供。 範例如下: ``` args = parser.parse_args() print(vars(args)) ``` 假設你執行的命令為: ``` python args_builder.py pdf2img -i ./input --pdf-zoom-factor 2.0 ``` `vars(args)` 可能會返回這樣的字典: ``` { 'input_dir': './input', 'pdf_zoom_factor': 2.0, 'pdf_file': None, 'subcommand': 'pdf2img' } ``` 這樣,`vars(args)` 就可以讓你以字典形式來檢查所有參數是否有值,例如使用 `any(vars(args).values())` 來判斷是否有任何參數值被提供。 總結來說,`vars()` 用於將對象(這裡是 `Namespace`)轉換成字典,以便更靈活地檢查或操作它的屬性。