2012-03-02 35 views
9

GNU getopt và các công cụ dòng lệnh sử dụng nó, cho phép các tùy chọn và đối số được xen kẽ, được gọi là tùy chọn hoán vị (xem http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt). Perop's Getopt :: Long module cũng hỗ trợ điều này (với qw (: config gnu_getopt)). argparse dường như không hỗ trợ (hoặc thậm chí đề cập đến) các tùy chọn hoán đổi.Lệnh đối số hoán vị argparse của Python có thể như gnu getopt?

Có nhiều câu hỏi SO liên quan đến lệnh arg/opt, nhưng không có câu hỏi nào trả lời câu hỏi này: Có thể argparse được thực hiện để hoán đổi thứ tự đối số như getopt không?

Các trường hợp sử dụng là một dòng lệnh chữ ký nguyên mẫu như GNU loại:

sort [opts] [files] 

trong đó 1) lựa chọn và các tập tin là hoán vị, và 2) trong danh sách tập tin có thể chứa số không hay nhiều đối số.

Ví dụ:

import argparse 
p = argparse.ArgumentParser(); 
p.add_argument('files',nargs='*',default=['-']); 
p.add_argument('-z',action='store_true') 

p.parse_args(['-z','bar','foo']) # ok 
p.parse_args(['bar','foo','-z']) # ok 
p.parse_args(['bar','-z','foo']) # not okay 
usage: ipython [-h] [-z] [files [files ...]] 

Tôi đã thử:

  • p.parse_known_args - không phàn nàn, nhưng không thực sự hoán vị hai và nó không Balk về lập luận trông giống như các tùy chọn không hợp lệ (ví dụ: - bogus hoặc -b above).
  • p.add_argument ('tệp', nargs = argparse.REMAINDER) - tùy chọn -z được đưa vào tệp trừ khi trước vị trí args
  • p.add_argument ('files', nargs = '*', action = ' nối thêm ');

Tôi muốn thực hiện điều gì đó gần nguyên mẫu sắp xếp GNU ở trên. Tôi không quan tâm đến cờ có thể được chỉ định cho mỗi tệp (ví dụ: -f tệp1 -f tệp2).

Trả lời

3

Tôi đã thấy không có gì dứt khoát trong tài liệu argparse nói rằng nó có thể hoặc không thể hoán đổi. Dựa trên các quan sát của riêng bạn, khi hoán vị thất bại, và các trích dẫn doc sau đây, tôi sẽ kết luận rằng nó không thể được thực hiện.

  1. Có đã là một mô-đun được đặt tên một cách rõ ràng 'getopt':

    Note Module getopt là một phân tích cú pháp cho các tùy chọn dòng lệnh mà API được thiết kế để làm quen cho người dùng của hàm C getopt(). Người dùng không quen với chức năng C getopt() hoặc ai muốn viết ít mã hơn và nhận được trợ giúp và thông báo lỗi tốt hơn nên xem xét bằng cách sử dụng mô-đun argparse thay thế.

  2. Thậm chí mặc định cho getopt không hoán vị, có một phương pháp nữa được xác định một cách rõ ràng tên gnu_getopt():

    Chức năng này hoạt động giống như getopt(), ngoại trừ việc GNU phong cách chế độ quét được sử dụng bởi mặc định. Điều này có nghĩa là các đối số tùy chọn và không tùy chọn có thể được trộn lẫn.

  3. Trong các tài liệu getopt, tài liệu tham khảo ở trên để argparse là tiếp tục phóng đại bởi sự bao gồm các nội dung sau:

    Lưu ý rằng một giao diện dòng lệnh tương đương có thể được sản xuất với ít mã và thông tin mới hơn giúp đỡ và thông báo lỗi bằng cách sử dụng các mô-đun argparse:

Agai n, không có gì dứt khoát, nhưng, với tôi, một phân chia rất sắc nét đang được rút ra giữa getopt và argparse với tài liệu ủng hộ/ủng hộ argparse.

Dưới đây là một ví dụ sử dụng gnu_getop() mà satifies -z [file [file]] thử nghiệm của bạn:

>>> args = 'file1 -z file2'.split() 
>>> args 
['file1', '-z', 'file2'] 
>>> opts, args = getopt.gnu_getopt(args, 'z') 
>>> opts 
[('-z', '')] 
>>> args 
['file1', 'file2'] 

Sửa 1: Tới hoán vị Yourself, với argparse

Lấy cảm hứng từ định nghĩa về "hoán vị" trong 'Sử dụng getopt 'trang bạn đã liên kết với,

Mặc định là để hoán đổi nội dung của argv trong khi quét vì vậy mà cuối cùng tất cả các tùy chọn không phải là ở cuối.

cách hoán đổi chuỗi arg trước khi chuyển nó đến parse_args()?

import argparse 

p = argparse.ArgumentParser(); 
p.add_argument('files',nargs='*',default=['-']); 
p.add_argument('-z',action='store_true') 

Lăn riêng bạn:

import re 

def permute(s, opts_ptn='-[abc]'): 
    """Returns a permuted form of arg string s using a regular expression.""" 
    opts = re.findall(opts_ptn, s) 
    args = re.sub(opts_ptn, '', s) 
    return '{} {}'.format(' '.join(opts), args).strip() 

>>> p.parse_args(permute('bar -z foo', '-[z]').split()) 
Namespace(files=['bar', 'foo'], z=True) 

Tận dụng getopt:

import getopt 

def permute(s, opts_ptn='abc'): 
    """Returns a permuted form of arg string s using `gnu_getop()'.""" 
    opts, args = getopt.gnu_getopt(s.split(), opts_ptn) 
    opts = ' '.join([''.join(x) for x in opts]) 
    args = ' '.join(args) 
    return '{} {}'.format(opts, args).strip() 

>>> p.parse_args(permute('bar -z foo', 'z').split()) 
Namespace(files=['bar', 'foo'], z=True) 
4

Dưới đây là một giải pháp nhanh chóng mà giải mã danh sách đối số một (tùy chọn, lập luận vị trí) cặp cùng một lúc.

import argparse 

class ExtendAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     items = getattr(namespace, self.dest, None) 
     if items is None: 
      items = [] 
     items.extend(values) 
     setattr(namespace, self.dest, items) 

parser = argparse.ArgumentParser() 
parser.add_argument('files', nargs='*', action=ExtendAction) 
parser.add_argument('-z', action='store_true') 
parser.add_argument('-v', action='count') 
parser.add_argument('args_tail', nargs=argparse.REMAINDER) 

def interleaved_parse(argv=None): 
    opts = parser.parse_args(argv) 
    optargs = opts.args_tail 
    while optargs: 
     opts = parser.parse_args(optargs, opts) 
     optargs = opts.args_tail 
    return opts 

print(interleaved_parse('-z bar foo'.split())) 
print(interleaved_parse('bar foo -z'.split())) 
print(interleaved_parse('bar -z foo'.split())) 
print(interleaved_parse('-v a -zv b -z c -vz d -v'.split())) 

Output:

Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True) 
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True) 
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True) 
Namespace(args_tail=[], files=['a', 'b', 'c', 'd'], v=4, z=True) 

Lưu ý: Đừng cố gắng sử dụng này với lập luận phi cờ khác (ngoài một nargs='*' đối số duy nhất và args_tail lập luận). Trình phân tích cú pháp sẽ không biết về các lời gọi trước đó của parse_args để nó sẽ lưu trữ giá trị sai cho các đối số không phải cờ này. Để giải quyết sự cố này, bạn có thể phân tích cú pháp đối số nargs='*' theo cách thủ công sau khi sử dụng interleaved_parse.

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