假設我有一個名爲myprog
的程序,它將一些文件名作爲輸入,並且我還希望使用命令行參數爲每個文件設置打開模式。 例如如何處理與argparse有關係的命令行參數?
myprog --input a.txt --mode r --input b.txt --input c.txt --mode a
這意味着打開文件a.txt
與模式r
,文件b.txt
沒有--mode阿根廷,所以用默認模式r
打開它,該文件c.txt
,使用a
模式打開它。
假設我有一個名爲myprog
的程序,它將一些文件名作爲輸入,並且我還希望使用命令行參數爲每個文件設置打開模式。 例如如何處理與argparse有關係的命令行參數?
myprog --input a.txt --mode r --input b.txt --input c.txt --mode a
這意味着打開文件a.txt
與模式r
,文件b.txt
沒有--mode阿根廷,所以用默認模式r
打開它,該文件c.txt
,使用a
模式打開它。
這是一個棘手的問題,因爲argparse不會讓您知道哪個--input
與某個--mode
相關聯。您可以改變命令的結構,使文件名和模式是由標記字符分隔:
myprog --input a.txt:r --input b.txt --input c.txt:a
顯然,這假設你沒有文件後綴名爲:<mode>
其中<mode>
是任何可接受文件模式。如果這是一個OK結構,那麼就像編寫自定義操作或類型來解析字符串並返回合適的對象一樣簡單。例如
def parse_fstr(s):
filename, _, mode = s.rpartition(':')
return (filename, mode or 'r')
其他解決方案可能涉及使用nargs='*'
然後解析出傳遞的參數列表。
最後,實現你所實際上要求不會有太大困難,我們需要做一個假設。假設將從左到右解析項目。鑑於圖書館的功能,這是唯一合理的選擇實施,據我所知...
鑑於實施,我們可以做到這一點與自定義類型和自定義Action。該類型只是一個結構,可以將filename
和mode
分組在一起。每當我們點擊一個--input
並將它追加到一個列表中(這是支持開箱的),我們將使用構造這種類型的新實例。接下來,我們將編寫一個自定義操作,以在每次插入--mode
參數時更新列表中最後一個「文件結構」的mode
。
import argparse
class FileInfo(object):
def __init__(self, name, mode='r'):
self.name = name
self.mode = mode
def __repr__(self):
return 'FileInfo(name={!r}, mode={!r})'.format(self.name, self.mode)
class UpdateMode(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
try:
last_file_info = namespace.input[-1]
except IndexError:
# No file-info added yet. Error.
parser.error('{} must come after an --input'.format(option_string or '--mode'))
last_file_info.mode = values
parser = argparse.ArgumentParser()
parser.add_argument('--input', action='append', type=FileInfo)
parser.add_argument('--mode', action=UpdateMode)
print(parser.parse_args())
我選擇拋出一個錯誤,如果--mode
任何--input
之前顯示出來,但如果2 --mode
遵循--input
,我只是覆蓋以前的值。如果您想要進行更多錯誤檢查,那麼在FileInfo
類中編寫更多代碼以確保在您更新模式時尚未設置任何模式。
是的,''parse_args'遍歷'argv'('sys.argv [1:]'),或者處理定位和選擇權。各自的'nargs'控制給每個'Action'分配多少個字符串。所以你的自定義Action類應該像廣告一樣工作。 – hpaulj
如果在命令行是這樣的:
myprog --input a.txt --mode r --input c.txt --mode a --input b.txt
這是確定添加一些像這樣的代碼:
import argparse
parser = argparser.ArgumentParser()
parser.add_argument('--input', action='append')
parser.add_argument('--mode', action='append')
args = parser.parse_args()
args_dict = vars(args)
然後你就可以分析參數對象,args_dict變量。值是這樣的:
$ python test.py --input test.txt --mode w --input test3.txt --input test2.txt --mode a
{'mode': ['w', 'a'], 'input': ['test.txt', 'test3.txt', 'test2.txt']}
可以遍歷都「輸入」鍵和「模式」在args_dict變量鍵,爲保持輸入列表中(它的「的test2.txt」這裏),你可以用'r'模式打開它。
但是,如果您的命令行必須寫類似:
myprog --input a.txt --mode r --input b.txt --input c.txt --mode a
我不認爲這是容易解析帶「R」模式下的b.txt,因爲argparse不知道哪個模式結合相對輸入...
獲得從@mgilson靈感的意見和答案,我已經找到了另一種方式來定義Action子類,使‘模式’輸入有用。
class ExtendReadOnlyAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
inputs = namespace.input
modes = getattr(namespace, self.dest)
if modes is None:
modes = []
modes.extend(['r' for i in range(len(inputs) - len(modes))])
modes[-1] = values
setattr(namespace, self.dest, modes)
而且客戶端代碼可以是這樣的:
import argparse
parser = argparser.ArgumentParser()
parser.add_argument('--input', action='append')
parser.add_argument('--mode', action=ExtendReadOnlyAction)
args = parser.parse_args()
args_dict = vars(args)
然後我們可以分析參數對象,args_dict變量更容易。如果在命令行是這樣的:
$ python test.py --input test.txt --mode w --input test2.txt --input test3.txt --mode a
結果將是:
{'mode': ['w', 'r', 'a'], 'input': ['test.txt', 'test2.txt', 'test3.txt']}
在其他特殊的方式,如果命令行是這樣的:
$ python test.py --input test.txt --mode w --input test2.txt --input test3.txt --input test4.txt
結果將是:
{'input': ['test.txt', 'test2.txt', 'test3.txt', 'test4.txt'], 'mode': ['w']}
而且n您可以更輕鬆地解析dict,輸入參數中的'test2.txt〜test4.txt'將具有默認'r'模式:)
如果您使用的是pycharm,則可以使用設置指定命令行參數。 –
那麼,問題是什麼? –
你保證每個'--input'都有對應的'--mode'嗎?如果是這樣,那麼你可以在'input'和'mode'上使用'append''動作,然後''壓縮'列表。如果沒有(根據你的例子看起來就像是這種情況),那麼事情就會變得更加困難,除非你願意重組命令行 - 例如'myprog --input a.text r --input b.txt --input c.txt a ...' – mgilson