2013-07-11 166 views
11

我正在嘗試使用​​模塊來解析命令行選項。Python argparse:可以被命名或位置的命令行參數

我想做一個可選的參數,可以是名稱或位置。例如,我想要myScript --username=batmanmyScript batman做同樣的事情。我也想myScript沒有用戶名是有效的。這可能嗎?如果是這樣,該怎麼辦?

我嘗試了類似於下面的代碼的各種東西沒有任何成功。

parser = argparse.ArgumentParser() 
group = parser.add_mutually_exclusive_group() 
group.add_argument("-u", "--user-name", default="admin") 
group.add_argument("user-name", default="admin") 
args = parser.parse_args() 

編輯:上面的代碼拋出異常說ValueError: mutually exclusive arguments must be optional

我在OS X 10.8.4上使用Python 2.7.2。

編輯:我嘗試了Gabriel Jacobsohn的建議,但是我無法在所有情況下都正常工作。

我嘗試這樣做:

parser = argparse.ArgumentParser() 
group = parser.add_mutually_exclusive_group() 
group.add_argument("-u", "--user-name", default="admin", nargs="?") 
group.add_argument("user_name", default="admin", nargs="?") 
args = parser.parse_args() 
print(args) 

和運行myScript batman將打印Namespace(user_name='batman'),但​​和myScript --user-name=batman將打印Namespace(user_name='admin')

我試圖改變名稱user-nameuser_name在第一add_argument線,有時導致了命名空間或錯誤,都batmanadmin取決於我如何運行該程序。

我試圖在第二add_argument線更名user_nameuser-name但會打印要麼Namespace(user-name='batman', user_name='admin')Namespace(user-name='admin', user_name='batman'),這取決於我如何運行該程序。

+0

我想提一下,我正在嘗試做的事情基本上與[Ack](http://beyondgrep.com/)對它的'--match'參數做的事情是一樣的。 –

+1

請看看這個[問題](http://stackoverflow.com/questions/17707234/how-to-create-an-argument-that-is-optional/17707752#17707752) – twil

+0

不知怎的,我沒有注意到這個問題, 。隨意將此問題標記爲該問題的重複。 –

回答

0

嘗試使用add_argument方法的「nargs」參數。 這種方式適用於我。 現在你可以添加用戶名兩次, ,所以你必須檢查它,並提出一個錯誤,如果你想。

import argparse 
if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument("-u", "--user-name", default="admin") 
    parser.add_argument("user_name", default="admin", nargs="?") 
    args = parser.parse_args() 
    print(args) 
+0

我在你的答案中嘗試了代碼。當我運行'myScript batman'但是'myScript -u batman'或'myScript -user-name = batman'運行正常時,它忽略了我的參數並將'user_name'的值設置爲'admin'。 –

4

這裏是我想你想要做的一切的解決方案:

import argparse 
if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument("-u", "--user-name", default="admin") 
    # Gather all extra args into a list named "args.extra" 
    parser.add_argument("extra", nargs='*') 
    args = parser.parse_args() 
    # Set args.user_name to first extra arg if it is not given and len(args.extra) > 0 
    if args.user_name == parser.get_default("user_name") and args.extra: 
     args.user_name = args.extra.pop(0) 
    print args 

如果運行​​或myScript --user-name=batmanargs.user_name被設置爲 '蝙蝠俠'。如果你做myScript batman,則args.user_name再次設置爲'蝙蝠俠'。最後,如果你只是做myScriptargs.user_name被設置爲'admin'。

另外,作爲額外的好處,您現在已將所有傳遞給存儲在args.extra中的腳本的額外參數。希望這可以幫助。

+0

我會將'args.username = args.extra [0]'更改爲'args.username = args.extra.pop(0)',這樣它就不會在兩個地方顯示出來。 – Perkins

+0

@Perkins:嗯......我喜歡那樣。它保持腳本更清潔。讓我來做 – iCodez

+0

我喜歡你的答案。我做了一個小改動,以避免在兩個地方使用默認用戶名。 –

7

ArgumentParser的工作原理是,在解析可選參數後,它總是檢查任何尾隨位置參數。因此,如果您有一個與可選參數同名的位置參數,並且它不會出現在命令行的任何位置,它肯定會覆蓋可選參數(使用其默認值或)。

坦率地說,這似乎是一個互斥組至少使用時的錯誤給我,因爲如果你有指定的參數明確這將是一個錯誤。

這就是說,我建議的解決方案是給postional參數一個不同的名稱。

parser = argparse.ArgumentParser() 
group = parser.add_mutually_exclusive_group() 
group.add_argument('-u','--username') 
group.add_argument('static_username',nargs='?',default='admin') 

然後在解析時,你如果存在使用可選用戶名,否則退回到位置static_username

results = parser.parse_args() 
username = results.username or results.static_username 

我意識到這不是一個特別整潔的解決方案,但我不認爲任何答案會是。