2012-07-12 34 views
12

Trong tập lệnh python của tôi, tôi muốn có thể sử dụng tham số đầu vào tùy chọn chỉ khi tham số tùy chọn khác đã được chỉ định. Ví dụ:python, argparse: cho phép tham số đầu vào khi một tham số khác được chỉ định

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

Nhưng KHÔNG:

$ python myScript.py --parameter2 value2 

Làm thế nào để làm điều này với argparse?

Cảm ơn!

+1

gì làm bạn muốn xảy ra nếu 'myScript.py --parameter2 value2 --parameter1 value1'? Đây là một trường hợp rất khó giải quyết nếu bạn muốn nó vượt qua. – mgilson

+1

http://bugs.python.org/issue11588 là một yêu cầu về lỗi đối với tính năng 'mutually_inclusive_group'. Điều đó sẽ không hoàn toàn hoạt động trong trường hợp này, vì '--parameter1' có thể xảy ra mà không có' --parameter2'. Đóng góp cho vấn đề đó nếu bạn có ý tưởng về cách thức này hoặc các ràng buộc liên quan có thể được thực hiện. – hpaulj

Trả lời

10

Sử dụng một hành động tùy chỉnh:

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()) 

này thậm chí có thể được thực hiện trong dễ dàng hơn một chút để duy trì cách nếu bạn OK với dựa vào một số hành vi không có giấy tờ của 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()) 

Trong ví dụ này, chúng tôi nhận được mặc định cho foo và đích đến của nó từ đối tượng hành động được trả về bởi add_argument (giá trị trả lại của add_argument không được ghi lại ở bất kỳ nơi nào tôi có thể tìm thấy). Điều này vẫn còn một chút mong manh (Nếu bạn muốn chỉ định một từ khóa type= cho đối số --foo chẳng hạn).

Cuối cùng, bạn có thể kiểm tra sys.argv trước khi phân tích cú pháp.

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

này được một chút khó khăn hơn nếu --parameter1 cũng có thể được kích hoạt bởi --p1, nhưng bạn sẽ có được ý tưởng. Sau đó, bạn có thể sử dụng

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

Lợi thế ở đây là không yêu cầu bất kỳ thứ tự cụ thể nào. (--p2 không cần theo dõi --p1 trên dòng lệnh). Và, như trước đây, bạn có thể nhận được danh sách các chuỗi lệnh sẽ kích hoạt hành động cụ thể của bạn thông qua thuộc tính option_strings được trả về bởi parser.add_argument(...). ví dụ.

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

Một ý tưởng sẽ được tự kiểm tra đầu ra gọi parser.parse_args() và nâng cao một ngoại lệ hay thất bại nếu --parameter2 được sử dụng nhưng không phải là --parameter1.

Bạn cũng có thể thử đặt custom action (cuộn xuống một chút) để --parameter2 kiểm tra xem có --parameter1 tồn tại bên trong không gian tên không.

Cuối cùng, bạn có thể thử sử dụng subparsers, mặc dù tôi không biết liệu nó có cho phép bạn chỉ định giá trị cho --parameter1 hay không.

2

Bạn có thể sử dụng parse_known_args() để kiểm tra xem --parameter1 đã được đưa ra chưa trước khi thêm --parameter2 vào trình phân tích cú pháp.

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 

Kết quả:

$ 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' sẽ không chính xác. – pmav99

Các vấn đề liên quan