2012-07-12 57 views
12

在我的python腳本中,我希望能夠使用可選的輸入參數只有當另一個可選參數已被指定。例如:python,argparse:當指定另一個參數時啓用輸入參數

$ python myScript.py --parameter1 value1 
$ python myScript.py --parameter1 value1 --parameter2 value2 

但不是:

$ python myScript.py --parameter2 value2 

如何做到這一點與argparse?

謝謝!

+1

你想發生,如果'myScript.py --parameter2值2 --parameter1 value1'什麼?如果你想讓它通過,這是一個很難處理的情況。 – mgilson 2012-07-12 15:54:26

+1

http://bugs.python.org/issue11588是'mutual_inclusive_group'功能的錯誤請求。這種情況在這種情況下並不適用,因爲'--parameter1'可以在沒有'--parameter2'的情況下發生。如果您有關於如何實施這個或相關約束的想法,可以對此問題做出貢獻。 – hpaulj 2014-02-25 23:38:14

回答

10

使用自定義操作:

import argparse 

foo_default=None  

class BarAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     didfoo=getattr(namespace,'foo',foo_default) 
     if(didfoo == foo_default): 
      parser.error("foo before bar!") 
     else: 
      setattr(namespace,self.dest,values) 

parser=argparse.ArgumentParser() 
parser.add_argument('--foo',default=foo_default) 
parser.add_argument('--bar',action=BarAction,help="Only use this if --foo is set") 

#testing. 
print parser.parse_args('--foo baz'.split()) 
print parser.parse_args('--foo baz --bar cat'.split()) 
print parser.parse_args('--bar dog'.split()) 

這甚至可以輕鬆一點來完成,如果你確定有依靠argparse的一些無證行爲,維護方式:

import argparse 

parser=argparse.ArgumentParser() 
first_action=parser.add_argument('--foo',dest='cat',default=None) 

class BarAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     didfoo=getattr(namespace,first_action.dest,first_action.default) 
     if(didfoo == first_action.default): 
      parser.error("foo before bar!") 
     else: 
      setattr(namespace,self.dest,values) 

parser.add_argument('--bar',action=BarAction, 
        help="Only use this if --foo is set") 

#testing. 
print parser.parse_args('--foo baz'.split()) 
print parser.parse_args('--foo baz --bar cat'.split()) 
print parser.parse_args('--bar dog'.split()) 

在在這個例子中,我們得到了foo的默認值,它是add_argument返回的操作對象的目的地(add_argument的返回值沒有記錄在我能找到的任何地方)。這仍然有點脆弱(例如,如果您想指定type=關鍵字與--foo參數)。

最後,您可以在解析之前檢查sys.argv

import sys 
if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv): 
    parser.error("parameter1 must be given if parameter2 is given") 

這變得有點比較麻煩,如果--parameter1也可以通過--p1觸發,但你的想法。那麼你可以使用

if (set(sys.argv).intersection(('--p2',...)) and 
    not set(sys.argv).intersection(('--p1',...))) 

這裏的好處是,它不需要任何特定的順序。 (--p2不需要在命令行上關注--p1)。和以前一樣,您可以通過parser.add_argument(...)返回的option_strings屬性來獲取將觸發您的特定操作的命令字符串列表。例如

import argparse 
import sys 
parser=argparse.ArgumentParser() 
action1=parser.add_argument('--foo') 
action2=parser.add_argument('--bar', 
          help="Only use this if --foo is set") 

argv=set(sys.argv) 
if ((argv & set(action2.option_strings)) and 
     not (argv & set(action1.option_strings))): 
       #^ set intersection 
    parser.error(' or '.join(action1.option_strings)+ 
        ' must be given with '+ 
        ' or '.join(action2.option_strings)) 
2

一個辦法是將手動檢查調用parser.parse_args()的輸出,並拋出一個異常,或者如果使用--parameter2--parameter1不是否則失敗。

您也可以嘗試設置custom action(向下滾動一下)至--parameter2檢查名稱空間內是否存在--parameter1

最後,您可以嘗試使用subparsers,但我不知道它是否會讓您指定--parameter1的值。

2

您可以使用parse_known_args()檢查--parameter1被添加--parameter2解析器之前給出。

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument('--parameter1', dest='p1') 
args = parser.parse_known_args()[0] 
if args.p1: 
    parser.add_argument('--parameter2', dest='p2') 
args = parser.parse_args() 

if args.p1: 
    print args.p1 
if args.p2: 
    print args.p2 

結果:

$ python myScript.py --parameter1 a 
a 
$ python myScript.py --parameter1 a --parameter2 b 
a 
b 
$ python myScript.py --parameter2 b 
usage: myScript.py [-h] [--parameter1 P1] 
myScript.py: error: unrecognized arguments: --parameter2 b 
+2

'--help'雖然會不準確。 – pmav99 2014-12-12 19:17:55