2010-08-11 60 views
11

Mã hiện tại của tôi trông giống như thế này. Nó cho phép tôi phân tích cú pháp nhiều tham số mà kịch bản chương trình của tôi nhận được. Có cách nào khác gần hơn với 'các phương pháp hay nhất' không? Tôi đã không nhìn thấy mã thực sự bằng cách sử dụng đầu ra của argparse, chỉ làm thế nào để thiết lập nó.Sử dụng đầu ra argparse cho các chức năng gọi

def useArguments(): 
    x = 0 
    while x <= 5: 
     if x == 0:      
      if args.getweather != None: 
       getWeather(args.getweather) 
     if x == 1: 
      if args.post != None: 
       post(args.post) 
     if x == 2: 
      if args.custompost != None: 
       custompost(args.custompost) 
     if x == 3: 
      if args.list != None: 
       listAccounts(args.list) 
     if x == 4: 
      if args.add != None: 
       addAccount(args.add[0]) 
     if x == 5: 
      if args.edit != None: 
       editAccount(args.edit[0]) 
     x = x + 1  


if __name__ == '__main__': 

    updateConfig() 

    parser = argparse.ArgumentParser(description='Post Yahoo weather to Twitter.', epilog="Report any bugs to [email protected]", prog='Program') 

    parser.add_argument('-a', '--add', nargs=1, help='Add a new account. Use the desired account name as an argument.') 
    parser.add_argument('-e', '--edit', nargs=1, choices=accountListSTR[:-1], help='Edit an account. Use the desired account name as an argument.') 
    parser.add_argument('-g', '--getweather', nargs='*', choices=accountListSTR, help='Get weather and post here. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-p', '--post', nargs='*', choices=accountListSTR, help='Post weather to Twitter. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-c', '--custompost', nargs=2, help='Post a custom message. Specify an account then type the message. Make sure you use "" around the message. Use "all" for all accounts.') 
    parser.add_argument('-l', '--list', action='store_const', const='all', help='List all accounts.') 
    parser.add_argument('--version', action='version', version='%(prog)s 0.3.3') 

    args = parser.parse_args() 

    useArguments() 

Trả lời

11

Bạn có thể cung cấp một tùy chỉnh action cho một cuộc tranh cãi bằng cách, và tôi trích dẫn:

đi qua một đối tượng mà thực hiện các API Action. Cách dễ nhất để thực hiện việc này là là để mở rộng argparse.Action, cung cấp phương thức __call__ thích hợp. Phương pháp __call__ nên chấp nhận bốn thông số:

  1. phân tích cú pháp: Đối tượng ArgumentParser trong đó có hành động này.
  2. không gian tên: Đối tượng vùng tên sẽ được trả về bởi parse_args(). Hầu hết các hành động thêm một thuộc tính cho đối tượng này.
  3. giá trị:. Các liên args dòng lệnh, với bất kỳ loại-chuyển đổi áp dụng (Type-chuyển đổi được xác định với đối số kiểu từ khóa để add_argument()
  4. option_string:. Chuỗi tùy chọn đã được sử dụng để gọi . hành động này đối số option_string là không bắt buộc, và sẽ vắng mặt nếu hành động được gắn liền với một đối số vị trí
+0

Trong trường hợp nào đây sẽ là phương pháp tốt nhất? Tôi không thể nhìn thấy một sử dụng cho tất cả các mã phụ. Nhưng sau đó một lần nữa, tôi hầu như không sử dụng lớp học vì vậy tôi có thể thiếu một cái gì đó. – avacariu

+1

@vlad, nó có thể được sử dụng để tự động gọi một hàm khi đối số được cung cấp, đó là những gì bạn đang làm sẽ tất cả các bản mẫu của bạn - bạn chỉ cần thực hiện các hàm là phương thức '__call__' của các lớp con thích hợp của 'argparse.Action'. Nhưng nếu bạn không "có được" lập trình hướng đối tượng, thì OK, bạn có thể làm theo cách của bạn (mặc dù vòng lặp đó và 'if x ==' kiểm tra thực sự dư thừa trong mọi trường hợp - chỉ cần thực hiện sau khi kiểm tra khác đối với những đối số nào hiện diện có thể đi theo các cuộc gọi thích hợp, không có giá trị gia tăng nào trong bản mẫu khác mà bạn sử dụng). –

+0

Đã chấp nhận câu trả lời này vì câu trả lời cho câu hỏi của tôi. Tôi * có thể * sẽ kết thúc việc này để tìm hiểu cách nó hoạt động; nhưng nó sẽ đòi hỏi nhiều thay đổi trong cách mã của tôi hiện đang hoạt động (đặc biệt là các hàm được liệt kê ở đó). Cảm ơn! – avacariu

4

Ngoại trừ --version, mà là rất phổ biến một lựa chọn, hành động mà bạn đã cung cấp khá giả coi là "lệnh con".

Tôi không biết gì về các chi tiết cụ argparse, như tôi vẫn chưa thử Python 2.7, nhưng bạn có thể có một cái nhìn tại các lệnh svn làm ví dụ, đây là một số giả cho dòng lệnh:

myprog [--version] <command> [<command opts>...] 

đâu <command> trong:

add|edit|getweather|post|custompost|list 

<command opts> những lựa chọn cụ thể để lệnh đó. Sử dụng optparse (đó là tương tự), điều này sẽ có nghĩa là lệnh của bạn sẽ được trả lại trong args, khi gọi parse_args, cho phép bạn làm điều gì đó như thế này:

opts, args = parser.parse_args() 
if opts.version: 
    ... 
else: 
    getattr("do_" + args[0])(*args[1:]) 

tôi thấy mô hình này đặc biệt hữu ích để gỡ lỗi, nơi tôi 'd cung cấp quyền truy cập vào các hàm nội bộ từ dòng lệnh và chuyển các đối số khác nhau để kiểm tra. Điều chỉnh lựa chọn trình xử lý lệnh phù hợp với dự án của riêng bạn.

+0

'argparse' thực sự cung cấp hỗ trợ cho chính xác mẫu này. ('optparse' không.) Tôi vẫn bị mắc kẹt trên Python 2.6 bản thân mình vì vậy tôi cũng không biết cụ thể, nhưng chúng được giải thích trong [documentation] (http://docs.python.org/ library/argparse.html # sub-commands). –

+0

Điều gì sẽ là lợi thế của việc này thay vì chỉ loại bỏ '--' khỏi các đối số của tôi. Tôi đoán cho người dùng cuối cùng nó sẽ trông giống nhau, phải không? Tôi đoán có nó như thế sẽ có ý nghĩa hơn cho người dùng cũng như b/c họ không thực sự chạy chương trình với các thông số tùy chỉnh mà là bảo nó làm điều gì đó. – avacariu

+0

@ vlad003: Đúng vậy. Người sử dụng của chương trình phải chọn một và chỉ một trong những "tùy chọn", do đó, thực sự họ đang lệnh cho chương trình của bạn. Tuy nhiên, các lệnh đó, có khả năng thực hiện các đối số. Một cách khác là viết các tập lệnh thực thi riêng biệt cho mỗi lệnh, thực hiện phân tích cú pháp arg riêng biệt trong mỗi lệnh và gọi một cơ sở mã chung để thực hiện. Ví dụ: các tập lệnh của bạn có thể được gọi là: myprog-list, myprog-add, vv Tuy nhiên tôi có thể thêm vào, khi bạn đang sử dụng argparse từ Python-2.7, có thể xử lý đối số rất thú vị. –

6

Xem http://docs.python.org/library/argparse.html#sub-commands:.

Một cách đặc biệt hiệu quả trong việc xử lý các lệnh con là kết hợp việc sử dụng phương thức add_subparsers() với các cuộc gọi tới set_defaults() để mỗi subparser biết hàm Python nào cần thực hiện.

Tóm lại:

parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers() 

weather_parser = subparsers.add_parser('get-weather') 
weather_parser.add_argument('--bar') 
weather_parser.set_defaults(function=get_weather) # ! 

args = parser.parse_args(['get-weather', '--bar', 'quux']) 
print args.function(args) 

Ở đây chúng ta tạo ra một subparser cho lệnh get-weather và gán chức năng get_weather với nó.

Lưu ý rằng tài liệu nói rằng từ khóa/thuộc tính có tên là func nhưng chắc chắn là function là của argparse 1.1.

Mã kết quả là một chút quá dài dòng vì vậy tôi đã công bố một gói nhỏ "argh" mà làm cho mọi thứ đơn giản hơn, ví dụ:

parser = argparse.ArgumentParser() 
add_commands(parser, [get_weather]) 
print dispatch(parser, ['get-weather', '--bar', 'quux']) 

"Argh" có thể làm nhiều hơn nhưng tôi sẽ cho stack overflow câu trả lời mà . :-)

+2

Liên quan đến chỉnh sửa gần đây của caffinatedmonkey ("Tôi sẽ không cho phép tràn ngăn xếp câu trả lời này" → "Tôi sẽ cho phép trả lời tràn ngăn xếp"). Phiên bản mới có vẻ ổn nhưng tôi thực sự có nghĩa là câu trả lời sẽ trở nên cồng kềnh vì tôi đã nhồi nhét quá nhiều thông tin vào vùng văn bản. =) –

+0

Bạn có chắc chắn phần 'func' /' function' vẫn đúng không? 'func' hoạt động tốt cho tôi ... –

+0

Không chỉ là cách tiếp cận subparsing xấu xí, nhưng có vẻ như chỉ cần vượt qua nhiệm vụ phân tích cú pháp đối số ở mức thấp hơn - bạn phải có các hàm riêng biệt để chuyển vào mỗi' func' mà sau đó gọi các hàm "thực" của bạn, hoặc các hàm thực của bạn phải sử dụng lệnh chung của args dict. Tôi đoán trước đây là tốt cho các chương trình lớn, nhưng nó có vẻ vô lý để giới thiệu rất nhiều lớp thêm vào một chương trình nhỏ.Tất cả cùng, subparsers có vẻ như là lựa chọn tốt nhất cho đến nay. –

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