2011-01-22 32 views
17

Nếu tôi có đối số '-a', '-b', '-c', '-d', với chức năng add_mutually_exclusive_group() thì chương trình của tôi sẽ chỉ phải sử dụng một trong số chúng. Có cách nào để kết hợp, để chương trình chỉ chấp nhận '-a 999 -b 999' hoặc '-c 999 -d 999'?Liệu argparse (python) có hỗ trợ các nhóm đối số độc quyền lẫn nhau không?

Edit: thêm một chương trình đơn giản cho rõ ràng hơn:

>>> parser = argparse.ArgumentParser() 
>>> group = parser.add_mutually_exclusive_group() 
>>> group.add_argument('-a') 
>>> group.add_argument('-b') 
>>> group.add_argument('-c') 
>>> group.add_argument('-d') 

Sau đó chỉ ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d có thể được gọi. Có thể có nhóm argparse nhóm loại trừ, để chỉ được gọi là ./app.py -a .. -b .. | ./app.py -c .. -d ..?

Trả lời

6

EDIT: Không sao. Bởi vì argparse làm cho sự lựa chọn khủng khiếp của việc phải tạo ra một tùy chọn khi gọi group.add_argument. Đó sẽ không phải là lựa chọn thiết kế của tôi. Nếu bạn đang tuyệt vọng cho tính năng này, bạn có thể thử làm việc đó với ConflictsOptionParser:

# exclusivegroups.py 
import conflictsparse 

parser = conflictsparse.ConflictsOptionParser() 
a_opt = parser.add_option('-a') 
b_opt = parser.add_option('-b') 
c_opt = parser.add_option('-c') 
d_opt = parser.add_option('-d') 

import itertools 
compatible_opts1 = (a_opt, b_opt) 
compatible_opts2 = (c_opt, d_opt) 
exclusives = itertools.product(compatible_opts1, compatible_opts2) 
for exclusive_grp in exclusives: 
    parser.register_conflict(exclusive_grp) 


opts, args = parser.parse_args() 
print "opts: ", opts 
print "args: ", args 

Vì vậy khi chúng ta gọi nó, chúng ta có thể thấy chúng tôi nhận được hiệu quả mong muốn.

$ python exclusivegroups.py -a 1 -b 2 
opts: {'a': '1', 'c': None, 'b': '2', 'd': None} 
args: [] 
$ python exclusivegroups.py -c 3 -d 2 
opts: {'a': None, 'c': '3', 'b': None, 'd': '2'} 
args: [] 
$ python exclusivegroups.py -a 1 -b 2 -c 3 
Usage: exclusivegroups.py [options] 

exclusivegroups.py: error: -b, -c are incompatible options. 

Thông điệp cảnh báo không thông báo cho bạn rằng cả hai '-a''-b' không phù hợp với '-c', tuy nhiên một thông báo lỗi thích hợp hơn có thể được chế tác. Câu trả lời sai, cũ hơn bên dưới. EDIT

TRỞ LÊN:[chỉnh sửa này là sai, mặc dù nó sẽ không chỉ là một thế giới hoàn hảo nếu argparse làm việc theo cách này?] câu trả lời trước đây của tôi thực sự là không chính xác, bạn sẽ có thể làm điều này với argparse bằng cách chỉ định một nhóm cho mỗi tùy chọn loại trừ lẫn nhau. Chúng tôi thậm chí có thể sử dụng itertools để tổng quát hóa quy trình. Và làm cho nó để chúng tôi không phải loại ra tất cả các kết hợp một cách rõ ràng:

import itertools 
compatible_opts1 = ('-a', '-b') 
compatible_opts2 = ('-c', '-d') 
exclusives = itertools.product(compatible_opts1, compatible_opts2) 
for exclusive_grp in exclusives: 
    group = parser.add_mutually_exclusive_group() 
    group.add_argument(exclusive_grp[0]) 
    group.add_argument(exclusive_grp[1]) 
+1

http://bugs.python.org/issue10984 có bản vá cho phép bạn đặt một đối số vào nhiều nhóm loại trừ lẫn nhau. Làm điều đó là một sự thay đổi dễ dàng. Việc sử dụng có ý nghĩa với các nhóm chồng chéo có liên quan nhiều hơn. – hpaulj

5

Chỉ cần vấp vào vấn đề này bản thân mình. Từ đọc của tôi về các tài liệu argparse, có vẻ không phải là một cách đơn giản để đạt được điều đó trong argparse. Tôi đã xem xét việc sử dụng parse_known_args, nhưng điều đó sẽ sớm tính một phiên bản có mục đích đặc biệt của argparse ;-)

Có thể báo cáo lỗi là theo thứ tự. Trong khi đó, nếu bạn sẵn sàng làm cho người dùng của mình thực hiện thêm một chút gõ, bạn có thể giả mạo nó với các nhóm con (như cách các đối số của git và svn làm việc), ví dụ:

subparsers = parser.add_subparsers() 
    p_ab = subparsers.add_parser('ab') 
    p_ab.add_argument(...) 

    p_cd = subparsers.add_parser('cd') 
    p_cd.add_argument(...) 

Không lý tưởng, nhưng ít nhất nó mang lại cho bạn tốt từ argparse mà không có quá nhiều tin xấu. Tôi đã kết thúc việc làm với các thiết bị chuyển mạch và chỉ sử dụng các hoạt động subparser với các subarguments cần thiết.

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