Sử dụng cùng một tùy chọn nhiều lần trong argparse của Python


82

Tôi đang cố gắng viết một tập lệnh chấp nhận nhiều nguồn đầu vào và thực hiện điều gì đó với mỗi nguồn. Một cái gì đó như thế này

./my_script.py \
    -i input1_url input1_name input1_other_var \
    -i input2_url input2_name input2_other_var \
    -i input3_url input3_name
# notice inputX_other_var is optional

Nhưng tôi không thể tìm ra cách làm điều này bằng cách sử dụng argparse. Có vẻ như nó được thiết lập để mỗi cờ tùy chọn chỉ có thể được sử dụng một lần. Tôi biết cách kết hợp nhiều đối số với một tùy chọn duy nhất ( nargs='*'hoặc nargs='+'), nhưng điều đó vẫn không cho phép tôi sử dụng -icờ nhiều lần. Làm cách nào để hoàn thành việc này?

Nói rõ hơn, những gì tôi muốn cuối cùng là một danh sách các chuỗi. Vì thế

[["input1_url", "input1_name", "input1_other"],
 ["input2_url", "input2_name", "input2_other"],
 ["input3_url", "input3_name"]]

Vậy tại sao không kết hợp nhiều đối số nguồn đầu vào với tùy chọn duy nhất đó?
TigerhawkT3

Vì mỗi nguồn đầu vào cũng cần có nhiều đối số chuỗi. Tôi muốn phải sử dụng cờ -i cho mỗi đầu vào và mỗi đầu vào sẽ chứa tất cả các chuỗi giữa các cờ -i liên tiếp. Tôi muốn nó làm việc như ffmpeg nơi bạn chỉ định đầu vào với -i
John Allard

Câu trả lời:


96

Đây là trình phân tích cú pháp xử lý một đối số 2 lặp lại tùy chọn - với các tên được xác định trong metavar:

parser=argparse.ArgumentParser()
parser.add_argument('-i','--input',action='append',nargs=2,
    metavar=('url','name'),help='help:')

In [295]: parser.print_help()
usage: ipython2.7 [-h] [-i url name]

optional arguments:
  -h, --help            show this help message and exit
  -i url name, --input url name
                        help:

In [296]: parser.parse_args('-i one two -i three four'.split())
Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']])

Điều này không xử lý được 2 or 3 argumenttrường hợp này (mặc dù tôi đã viết một bản vá cách đây một thời gian cho một lỗi / sự cố Python sẽ xử lý một phạm vi như vậy).

Làm thế nào về một định nghĩa đối số riêng biệt với nargs=3metavar=('url','name','other')?

Bộ tuple metavarcũng có thể được sử dụng với nargs='+'nargs='*'; 2 chuỗi được sử dụng là [-u A [B ...]]hoặc [-u [A [B ...]]].


1
Thật tuyệt! Tôi thích cách hàm trợ giúp hiển thị những gì các thành phần riêng lẻ của tùy chọn nhiều phần thể hiện. Tôi sẽ sử dụng cái này!
John Allard

48

Cái này đơn giản; chỉ cần thêm cả hai action='append'nargs='*'(hoặc '+').

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='append', nargs='+')
args = parser.parse_args()

Sau đó, khi bạn chạy nó, bạn nhận được

In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i
...: nput2_name input2_other_var -i input3_url input3_name

In [33]: args.i
Out[33]:
[['input1_url', 'input1_name', 'input1_other_var'],
 ['input2_url', 'input2_name', 'input2_other_var'],
 ['input3_url', 'input3_name']]

2
Cảm ơn, chính xác những gì tôi cần! : D Side lưu ý: mặc định có thể cần phải được danh sách loại / mảng, hoặc Argparse sẽ thất bại
Tarwin

22

-inên được cấu hình để chấp nhận 3 đối số và sử dụng appendhành động.

>>> p = argparse.ArgumentParser()
>>> p.add_argument("-i", nargs=3, action='append')
_AppendAction(...)
>>> p.parse_args("-i a b c -i d e f -i g h i".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])

Để xử lý một giá trị tùy chọn, bạn có thể thử sử dụng một loại tùy chỉnh đơn giản. Trong trường hợp này, đối số tới -ilà một chuỗi được phân tách bằng dấu phẩy, với số lượng phân tách được giới hạn ở 2. Bạn sẽ cần phải xử lý sau các giá trị để đảm bảo có ít nhất hai giá trị được chỉ định.

>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append')
>>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']])

Để kiểm soát nhiều hơn, hãy xác định một hành động tùy chỉnh. Cái này mở rộng tích hợp sẵn _AppendAction(được sử dụng bởi action='append'), nhưng chỉ thực hiện một số kiểm tra phạm vi về số lượng đối số được cung cấp -i.

class TwoOrThree(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        if not (2 <= len(values) <= 3):
            raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values)))
        super(TwoOrThree, self).__call__(parser, namespace, values, option_string)

p.add_argument("-i", nargs='+', action=TwoOrThree)

1
Xuất sắc! Cảm ơn sự giúp đỡ của bạn.
John Allard

2
Điều này không hoàn toàn làm những gì bạn muốn; Tôi đã bỏ lỡ đó inputX_other_varlà tùy chọn.
chepner

Tôi chỉ quay lại để nhận xét như vậy, cách của bạn yêu cầu tất cả các vars. Nó đang đi đúng hướng!
John Allard

1
OK, đã cập nhật một số tùy chọn để xử lý đối số thứ 3 tùy chọn.
chepner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.