2016-03-06 15 views
9

Tôi đã viết một số chương trình python dòng lệnh và sử dụng argparse để làm điều đó. Tôi đã được cấu trúc mã của tôi phần nào như sau.Giải quyết các đối số từ argparse

def main(arg1, arg2): 
    # magic 
    pass 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 

    args = parser.parse_args() 

    main(args.arg1, args.arg2) 

Nó thực sự siêu khó chịu phải gọi ra arg1arg2 3 lần. Tôi hiểu phải làm điều đó hai lần.

Có cách nào để xử lý không gian tên được trả về bởi hàm parse_args dưới dạng bộ tuple không? Hoặc tốt hơn như là một tuple và một dict cho args tùy chọn và làm giải nén?

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 
    parser.add_argument('--opt-arg', default='default_value') 

    args, kwargs = parser.magic_method_call_that_would_make_my_life_amazing() 

    # I get goosebumps just thinking about this 
    main(*args, **kwargs) 

Trả lời

3

https://docs.python.org/3/library/argparse.html#the-namespace-object

Lớp này là cố tình đơn giản, chỉ là một lớp con đối tượng với một chuỗi đại diện có thể đọc được. Nếu bạn muốn có cái nhìn dict giống như các thuộc tính, bạn có thể sử dụng các tiêu chuẩn thành ngữ Python, vars():

>>> 
>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument('--foo') 
>>> args = parser.parse_args(['--foo', 'BAR']) 
>>> vars(args) 
{'foo': 'BAR'} 

Lưu ý rằng một trong những tiến bộ lớn, hoặc thay đổi ít nhất, từ optparse đến argparse là các đối số vị trí, chẳng hạn như đối số của bạn, được xử lý giống như tùy chọn. Cả hai đều xuất hiện trong đối tượng argsNamespace. Trong optparse, các vị trí chỉ là phần còn lại từ việc phân tích cú pháp các tùy chọn được xác định. Bạn có thể nhận được tác dụng tương tự trong argparse bởi omiting đối số của bạn và sử dụng parse_known_args:

parser = argparse.ArgumentParser() 
args, extras = parser.parse_known_args() 

args bây giờ là một không gian tên, và extras một danh sách. Sau đó bạn có thể gọi hàm của bạn như:

myfoo(*extras, **vars(args)) 

Ví dụ:

In [994]: import argparse 
In [995]: def foo(*args, **kwargs): 
    .....:  print(args) 
    .....:  print(kwargs) 
    .....:  
In [996]: parser=argparse.ArgumentParser() 
In [997]: parser.add_argument('-f','--foo') 
Out[997]: _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None) 
In [998]: args,extras = parser.parse_known_args(['-f','foobar','arg1','arg2']) 
In [999]: args 
Out[999]: Namespace(foo='foobar') 
In [1000]: extras 
Out[1000]: ['arg1', 'arg2'] 
In [1001]: foo(*extras, **vars(args)) 
('arg1', 'arg2') 
{'foo': 'foobar'} 

Cùng argparse đoạn cho thấy bạn có thể định nghĩa lớp Namespace của riêng bạn.Nó sẽ không khó để xác định một trong đó hoạt động như một từ điển (để sử dụng như **args) và như không gian tên. Tất cả argparse yêu cầu là nó hoạt động với getattrsetattr.

In [1002]: getattr(args,'foo') 
Out[1002]: 'foobar' 
In [1004]: setattr(args,'bar','ugg') 
In [1005]: args 
Out[1005]: Namespace(bar='ugg', foo='foobar') 

một tính năng Python chuẩn cho phép tôi vượt qua vars(args) như một tuple:

In [1013]: foo(*vars(args).items()) 
(('foo', 'foobar'), ('bar', 'ugg')) 
{} 

Đối với một câu trả lời tương tự từ cuối tháng Giêng: https://stackoverflow.com/a/34932478/901925

Neatly pass positional arguments as args and optional arguments as kwargs from argpase to a function

Ở đó tôi đưa ra ý tưởng về cách để tách 'vị trí' khỏi 'tùy chọn' sau khi phân tích cú pháp.


Dưới đây là một lớp không gian tên tùy chỉnh bao gồm, trong API của nó, một phương tiện để trở về chính nó như là một cuốn từ điển:

In [1014]: class MyNameSpace(argparse.Namespace): 
    ......:  def asdict(self): 
    ......:   return vars(self) 
    ......:  
In [1015]: args = parser.parse_args(['-f','foobar'], namespace=MyNameSpace()) 
In [1016]: args 
Out[1016]: MyNameSpace(foo='foobar') 
In [1017]: foo(**args.asdict()) 
() 
{'foo': 'foobar'} 

ý tưởng khác - sử dụng một trong những nhiều nargs (2, '*', '+') cho đối số vị trí. Sau đó, bạn chỉ có một tên để nhập khi chuyển nó vào hàm của bạn.

parser.add_argument('pos',nargs='+') 
args = ... 
args.pos # a list, possibly empty 
foo(*args.pos, **vars(args)) 
4

là gì sai với việc

if __name__ == '__main__': 
    # do argparse stuff as above 
    main(args) 

Đó là, tại sao bạn nên treo lên về cho main() đối số vị trí?

Thành thật mà nói, tôi thường làm đối số phân tích cú pháp a) [cho tập lệnh nhỏ, v.v.] ở đầu mô-đun, cung cấp cho tôi biến số nằm trong phạm vi của tất cả các hàm hoặc b) [thường] bên trong main() nếu tôi sử dụng thành ngữ của bạn:

def parse_arguments(): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 
    args = parser.parse_args() 
    return args 

def main(): 
    args = parse_arguments() 
    # do stuff with args.arg1 and args.arg2 
+1

Tôi không muốn đóng gói arg vào bộ túp cho chức năng chính của mình nếu tôi nhập/gọi nó từ gói khác. Tôi rất thích lời gọi phương thức 'parse_arguments'. Tôi thực sự yêu điều đó. –

5

Bạn có thể thấy câu hỏi tương tự được hỏi here.

Chỉnh sửa: Tìm cách không sử dụng phương pháp nội bộ, tôi đã tìm thấy this discussion đề xuất sử dụng vars(). Đây hoạt động khá tốt:

import argparse 

def main(arg1, arg2): 
    print arg1, arg2 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 

    args = parser.parse_args() 
    main(**vars(args)) 
+0

Đây là một câu trả lời tuyệt vời .... Tôi muốn được gặp rắc rối bởi thiết kế thư viện hơn là dựa vào cái gì đó không phải là một phần của api công cộng bởi vì tôi là một weeny và tôi kết thúc cuối cùng trong cuộc sống. –

+0

Chúc mừng @BenHoff :-) Bạn có thể [chấp nhận] (http://stackoverflow.com/help/someone-answers) câu trả lời của tôi nếu nó phù hợp với bạn. –

+0

xin lỗi tôi đã thiếu một _but_ trong đó. Đây là một câu trả lời tuyệt vời .... ** nhưng ** Tôi muốn được gặp rắc rối bởi thiết kế thư viện hơn là dựa vào cái gì đó không phải là một phần của api công cộng bởi vì tôi là một weeny và tôi kết thúc cuối cùng trong cuộc sống. –

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