2012-12-12 28 views
5

Tôi có đoạn code sau để tạo một container mà giả vờ cư xử như các thiết lập của tất cả các số nguyên tố (trên thực tế ẩn một bài kiểm tra thủ memoised brute-force)Python argparse lựa chọn từ một tập vô hạn

import math 

def is_prime(n): 
    if n == 2 or n == 3: 
     return True 
    if n == 1 or n % 2 == 0: 
     return False 
    else: 
     return all(n % i for i in xrange(3, int(1 + math.sqrt(n)), 2)) 


class Primes(object): 

    def __init__(self): 
     self.memo = {} 

    def __contains__(self, n): 
     if n not in self.memo: 
      self.memo[n] = is_prime(n) 
     return self.memo[n] 

Điều đó có vẻ được làm việc cho đến nay:

>>> primes = Primes() 
>>> 7 in primes 
True 
>>> 104729 in primes 
True 
>>> 100 in primes 
False 
>>> 100 not in primes 
True 

Nhưng nó không chơi độc đáo với argparse:

>>> import argparse as ap 
>>> parser = ap.ArgumentParser() 
>>> parser.add_argument('prime', type=int, choices=primes, metavar='p') 
_StoreAction(option_strings=[], dest='prime', nargs=None, const=None, default=None, type=<type 'int'>, choices=<__main__.Primes object at 0x7f4e21783f10>, help=None, metavar='p') 
>>> parser.parse_args(['7']) 
Namespace(prime=7) 
>>> parser.parse_args(['11']) 
Namespace(prime=11) 
>>> parser.parse_args(['12']) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/argparse.py", line 1688, in parse_args 
    args, argv = self.parse_known_args(args, namespace) 
    File "/usr/lib/python2.7/argparse.py", line 1720, in parse_known_args 
    namespace, args = self._parse_known_args(args, namespace) 
    File "/usr/lib/python2.7/argparse.py", line 1929, in _parse_known_args 
    stop_index = consume_positionals(start_index) 
    File "/usr/lib/python2.7/argparse.py", line 1885, in consume_positionals 
    take_action(action, args) 
    File "/usr/lib/python2.7/argparse.py", line 1778, in take_action 
    argument_values = self._get_values(action, argument_strings) 
    File "/usr/lib/python2.7/argparse.py", line 2219, in _get_values 
    self._check_value(action, value) 
    File "/usr/lib/python2.7/argparse.py", line 2267, in _check_value 
    tup = value, ', '.join(map(repr, action.choices)) 
TypeError: argument 2 to map() must support iteration 

Các docs chỉ nói rằng

Bất kỳ đối tượng có hỗ trợ trong điều hành có thể được thông qua như là sự lựa chọn giá trị, các đối tượng để dict, bộ đối tượng, container tùy chỉnh, vv là tất cả được hỗ trợ.

Rõ ràng là tôi không muốn lặp lại "bộ" số nguyên tố vô hạn. Vậy tại sao heck là argparse cố gắng để map số nguyên tố của tôi? Nó không chỉ cần innot in?

Trả lời

4

Dường như đây là lỗi tài liệu. Thư viện dưới dạng văn bản yêu cầu đối số choices không chỉ là vùng chứa mà còn có thể lặp lại, Nó cố gắng liệt kê các tùy chọn có sẵn, tùy chọn này sẽ không hoạt động cho trường hợp của bạn. Bạn có thể cố gắng để hack nó bằng cách cho nó một giả __iter__ mà chỉ trả về một số chuỗi thông tin.

Bạn cũng có thể muốn gửi lỗi này dưới dạng lỗi trong trình theo dõi lỗi Python, vì hành vi thực sự bị mâu thuẫn với tài liệu.

+0

Cảm ơn, tôi đã tạo một vấn đề như bạn đã đề xuất [ở đây] (http://bugs.python.org/issue16697). – wim

5

Nguồn nơi bạn đang nhận được ngoại lệ là khá rõ ràng, check it out:

if action.choices is not None and value not in action.choices: 
    tup = value, ', '.join(map(repr, action.choices)) 
    msg = _('invalid choice: %r (choose from %s)') % tup 
    raise ArgumentError(action, msg) 

Vui lòng cung tự nó là tốt. Nó borks trên cố gắng in ra một thông báo lỗi hữu ích, nơi nó đang cố gắng để cung cấp cho bạn tất cả các lựa chọn có thể. Tôi cho rằng nếu bạn định nghĩa trình lặp để chỉ trả về một cái gì đó có dạng repr của chuỗi primes, bạn có thể hack nó để làm điều đúng đắn.

1

choices dành cho các đối số mà bạn có thể liệt kê tất cả các giá trị được phép (một tập hợp hữu hạn (nhỏ)). Các tài liệu nên rõ ràng hơn về nó.

primes là tập hợp vô hạn. Bạn có thể đặt tham số type để tăng ValueError cho số không phải số nguyên tố.

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