2012-01-26 23 views
23

Tôi gặp sự cố nhỏ với argparse. Tôi có một tùy chọn xlimxrange của một âm mưu. Tôi muốn có thể chuyển số như -2e-5. Tuy nhiên, điều này không có tác dụng - argparse diễn giải đây là một đối số vị trí. Nếu tôi làm -0.00002 hoạt động: argparse sẽ đọc số này làm số âm. Có thể đọc được trong -2e-3 không?Python Argparse: Vấn đề với các đối số tùy chọn là số âm

Mã này là dưới đây, và một ví dụ về làm thế nào tôi sẽ chạy nó là:

./blaa.py --xlim -2.e-3 1e4 

Nếu tôi làm như sau hoạt động:

./blaa.py --xlim -0.002 1e4 

Mã:

parser.add_argument('--xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 

Trong khi tôi có thể làm cho nó hoạt động theo cách này, tôi thực sự sẽ có thể sử dụng ký pháp khoa học. Ai có ý tưởng gì không?

Cheers

+0

Trích dẫn '-2e-5' có trợ giúp không? – nmichaels

+0

Theo http://code.google.com/p/argparse/issues/detail?id=37, nó phải được sửa. Kiểm tra xem phiên bản của argparse bạn có là mới hơn hay giống nhau. – favoretti

+0

@nmichaels Xin chào, ý của bạn là "-2e-5"? Nó không hoạt động không may, tôi nghĩ nó vẫn diễn giải nó như một đối số. Lỗi chính xác từ './blah.py -xlim" -.2e-5 "1e5' là --xlim: 2 đối số dự kiến. Nếu tôi sử dụng \ - nó nghĩ rằng một chuỗi của nó và sau đó than phiền bởi vì nó phải là một phao – Ger

Trả lời

11

Như đã chỉ ra bởi các ý kiến, vấn đề là một tiền tố - được phân tách như một tùy chọn thay vì là một cuộc tranh cãi. One way để workaround this is change các prefix used for options with prefix_chars argument:

#!/usr/bin/python 
import argparse 

parser = argparse.ArgumentParser(prefix_chars='@') 
parser.add_argument('@@xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Example output:

$ ./blaa.py @@xlim -2.e-3 1e4 
Namespace(xlim=[-0.002, 10000.0]) 

Edit: Alternatively, bạn can keep using - as separator, pass xlim as a single giá trị và sử dụng hàm trong type để triển khai phân tích cú pháp của riêng bạn:

#!/usr/bin/python 
import argparse 

def two_floats(value): 
    values = value.split() 
    if len(values) != 2: 
     raise argparse.ArgumentError 
    values = map(float, values) 
    return values 

parser = argparse.ArgumentParser() 
parser.add_argument('--xlim', 
        help = 'X axis limits', 
        action = 'store', type=two_floats, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Ví dụ outp ut:

$ ./blaa.py --xlim "-2e-3 1e4" 
Namespace(xlim=[-0.002, 10000.0]) 
+0

Tôi thực sự muốn giữ' -' làm dấu tách vì vậy tôi đã thực hiện phân tích cú pháp thô của sys .argv trước khi tôi gọi parse_args(). Cách tôi đã làm nó là trong một bình luận ở trên, nhưng cách của bạn là tốt hơn nhiều. Cảm ơn! – Ger

3

Nếu bạn đang lên đến sửa đổi argparse.py bản thân, bạn có thể thay đổi khớp số âm để xử lý ký hiệu khoa học:

Trong class _ActionsContainer.__init__()

self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$') 

Hoặc sau khi tạo phân tích cú pháp, bạn có thể đặt parser._negative_number_matcher thành giá trị này. Cách tiếp cận này có thể có vấn đề nếu bạn đang tạo nhóm hoặc subparsers, nhưng nên làm việc với một trình phân tích cú pháp đơn giản.

19

Một giải pháp thay thế mà tôi đã tìm thấy là báo giá trị, nhưng thêm khoảng trắng. Đó là,

./blaa.py --xlim " -2.e-3" 1e4 

cách argparse này sẽ không nghĩ -2.e-3 là một tên tùy chọn vì ký tự đầu tiên không phải là một gạch nối-dash, nhưng nó vẫn sẽ được chuyển đổi đúng cách để một phao vì phao (chuỗi) bỏ qua dấu cách ở bên trái.

+1

đẹp! Làm việc cho tôi trong một ngôn ngữ hoàn toàn khác nhau/môi trường cũng –

+0

Tôi thực hiện một tiền xử lý nhỏ quét sys.argv cho "xlim" và thêm một không gian để bắt đầu (thông qua câu trả lời của bạn). Tôi đặt điều này trước khi cuộc gọi đến argparse, và nó có vẻ là làm việc tốt ... 'cho indx trong phạm vi (len (sys.argv) - 1): nếu 'xlim' trong sys.argv [indx]: sys.argv [indx + 1] = '{0}' định dạng (sys.argv [indx + 1]) ' – jeremiahbuddha

+0

Điều này cũng hoạt động trong mô-đun ngọn lửa argparse –

3

Đây là mã tôi sử dụng. (Nó tương tự như jeremiahbuddha nhưng nó trả lời câu hỏi trực tiếp hơn vì nó đề cập đến các số âm.)

Đặt này trước khi gọi argparse.ArgumentParser()

for i, arg in enumerate(sys.argv): 
    if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg 
+0

câu trả lời tốt nhất và dễ nhất cho lỗi này lâu dài – mxmlnkn

2

workaround khác là để vượt qua trong đối số sử dụng '=' biểu tượng ngoài việc trích dẫn các đối số - tức là, --xlim="-2.3e14"

1

Lấy cảm hứng từ cách tiếp cận andrewfn, tôi đã tạo một hàm trợ giúp riêng biệt để thực hiện chức năng số sys.argv:

def _tweak_neg_scinot(): 
    import re 
    import sys 
    p = re.compile('-\\d*\\.?\\d*e', re.I) 
    sys.argv = [' ' + a if p.match(a) else a for a in sys.argv] 

Các regex tìm kiếm:

  • -: một dấu hiệu tiêu cực
  • \\d*: zero hoặc nhiều chữ số (cho các giá trị kỳ quặc định dạng giống như -.5e-2 hoặc -4354.5e-6)
  • \\.?: một khoảng thời gian tùy chọn (ví dụ, -2e-5 là hợp lý)
  • \\d*: một bộ số không hoặc nhiều chữ số khác (cho những thứ như -2e-5-7.e-3)
  • e: để khớp với điểm đánh dấu số mũ

re.I làm cho nó khớp với cả hai -2e-5-2E-5. Sử dụng p.match có nghĩa là nó chỉ tìm kiếm từ đầu mỗi chuỗi.

0

Nếu bạn chỉ định giá trị cho lựa chọn của bạn với một dấu bằng, argparse sẽ không đối xử với nó như một lựa chọn riêng biệt, thậm chí nếu nó bắt đầu với -:

./blaa.py --xlim='-0.002 1e4' 
# As opposed to --xlim '-0.002 1e4' 

Và nếu giá trị không có khoảng trống trong nó, bạn có thể thả các dấu ngoặc kép:

./blaa.py --xlim=-0.002 

Xem: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html

với điều này, không có cần phải viết bạn r own type= trình phân tích cú pháp hoặc xác định lại ký tự tiền tố từ - đến @ làm câu trả lời được chấp nhận.

+0

Điều này không hoạt động trong trường hợp cụ thể này vì --- xlim mong đợi hai đối số (nargs = 2). Đó là, trừ khi bạn muốn thay đổi quy ước để chương trình của bạn _requires_ người gọi để mã hóa hai giá trị dưới dạng một chuỗi, và chương trình của bạn sau đó thực hiện tách. – itub

+0

Ah, điểm tốt @itub. Nếu 'nargs = 2' là yêu cầu VÀ bất kỳ một trong hai giá trị tùy chọn đều bắt đầu bằng dấu gạch ngang, thì không có xung quanh nó. – mksios