Tôi cảm thấy như có một chút hạn chế với sub_parsers trong argparse, nếu nói, bạn có một bộ công cụ có thể có các tùy chọn tương tự có thể trải rộng trên các cấp độ khác nhau. Có thể hiếm khi có tình huống này, nhưng nếu bạn đang viết mã có thể cắm/mô-đun, nó có thể xảy ra.
Tôi có ví dụ sau. Nó là xa vời và không được giải thích vào lúc này bởi vì nó là khá muộn, nhưng ở đây nó đi:
Usage: tool [-y] {a, b}
a [-x] {create, delete}
create [-x]
delete [-y]
b [-y] {push, pull}
push [-x]
pull [-x]
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a')
parser_a.add_argument('-x', action = 'store_true')
subparsers_a = parser_a.add_subparsers(dest = 'sub_command')
parser_a_create = subparsers_a.add_parser('create')
parser_a_create.add_argument('-x', action = 'store_true')
parser_a_delete = subparsers_a.add_parser('delete')
parser_a_delete.add_argument('-y', action = 'store_true')
parser_b = subparsers.add_parser('b')
parser_b.add_argument('-y', action = 'store_true')
subparsers_b = parser_b.add_subparsers(dest = 'sub_command')
parser_b_create = subparsers_b.add_parser('push')
parser_b_create.add_argument('-x', action = 'store_true')
parser_b_delete = subparsers_b.add_parser('pull')
parser_b_delete.add_argument('-y', action = 'store_true')
print parser.parse_args(['-x', 'a', 'create'])
print parser.parse_args(['a', 'create', '-x'])
print parser.parse_args(['b', '-y', 'pull', '-y'])
print parser.parse_args(['-x', 'b', '-y', 'push', '-x'])
Output
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='b', sub_command='pull', x=False, y=True)
Namespace(command='b', sub_command='push', x=True, y=True)
Như bạn có thể thấy, rất khó để phân biệt nơi dọc theo chuỗi, mỗi đối số được thiết lập. Bạn có thể giải quyết vấn đề này bằng cách thay đổi tên cho mỗi biến. Ví dụ: bạn có thể đặt 'dest' thành 'x', 'a_x', 'a_create_x', 'b_push_x', v.v., nhưng điều đó sẽ gây khó khăn và khó phân tách.
Một giải pháp thay thế là dừng ArgumentParser khi nó đạt đến một tiểu ban và chuyển các đối số còn lại sang một trình phân tích cú pháp độc lập khác, để nó có thể tạo ra các đối tượng riêng biệt. Bạn có thể cố gắng đạt được điều đó bằng cách sử dụng 'parse_known_args()' và không xác định đối số cho mỗi tiểu nhóm. Tuy nhiên, điều đó sẽ không tốt vì bất kỳ đối số chưa được phân tích cú pháp nào từ trước sẽ vẫn ở đó và có thể gây nhầm lẫn cho chương trình.
Tôi cảm thấy một giải pháp hơi rẻ nhưng hữu ích là để argparse giải thích các đối số sau dưới dạng chuỗi trong danh sách. Điều này có thể được thực hiện bằng cách thiết lập tiền tố cho một null-terminator '\ 0' (hoặc một số khác 'khó sử dụng' nhân vật) - nếu tiền tố là trống rỗng, mã sẽ ném một lỗi, ít nhất là trong Python 2,7. 3.
Ví dụ:
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a' prefix_chars = '\0')
parser_a.add_argument('args', type = str, nargs = '*')
print parser.parse_args(['-xy', 'a', '-y', '12'])
Output:
Namespace(args=['-y', '12'], command='a', x=True, y=True)
Lưu ý rằng nó không tiêu thụ -y
tùy chọn thứ hai. Sau đó, bạn có thể chuyển kết quả 'args' sang một ArgumentParser khác.
Nhược điểm:
- Trợ giúp có thể không được xử lý tốt. Sẽ phải thực hiện một số giải pháp khác với các lỗi này
- Lỗi gặp phải có thể khó theo dõi và yêu cầu một số nỗ lực bổ sung để đảm bảo các thông báo lỗi được ghép đúng cách.
- Chi phí đầu tư ít hơn một chút được kết hợp với nhiều ArgumentParsers.
Nếu có ai có thêm thông tin về điều này, vui lòng cho tôi biết.
Công ty tôi đang làm việc cho có v2.6 ban đầu để sử dụng argparse là một vấn đề ở chỗ nó sẽ phải được đưa vào như một thư viện bên ngoài và chỉ được nạp nếu cần thiết. Từ xa không thể, chỉ là không lý tưởng. Đối với thư viện cmdln, cung cấp cho tôi một chút chức năng cơ bản mà tôi không muốn tạo lại. Điều đó nói rằng tôi phản đối việc sử dụng cái gì khác. – tima