2012-12-12 31 views
5

我有下面的代碼來創建它假裝表現得像集合所有素數(實際上隱藏了memoised蠻力素試驗)的Python argparse選擇從一組無限

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] 

這似乎是一個容器到目前爲止,被工作:

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

但它不與​​很好打:

>>> 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 

docs只想說,

支持的運營商可以作爲選擇傳遞 值,那麼字典對象,對象集合,自定義容器等任何對象都支持的所有 。

顯然我不想迭代素數的無限「集合」。那麼爲什麼到底是​​試圖map我的素數?是不是隻需要innot in

回答

4

它似乎是一個文檔錯誤。作爲書面的圖書館要求choices參數不只是一個容器,但也可迭代,它試圖列出可用的選項,這是不適合你的情況。你可以嘗試給它一個假的__iter__,它只是返回一些信息字符串。

您可能還想將其作爲Python錯誤跟蹤器中的錯誤提交,因爲行爲確實與文檔相矛盾。

+0

謝謝,我創建了一個問題,如你所建議[這裏](http://bugs.python.org/issue16697)。 – wim

5

源在那裏你得到的例外是很清楚的,檢查出來:

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) 

檢查本身是好的。它試圖打印出有用的錯誤信息,它試圖給你所有可能的選擇。我想如果你定義迭代器只返回repr字符串primes,你可能會破解它來做正確的事情。

1

choices適用於您可以枚舉所有允許的值(有限(小)集)的參數。文檔應該更清楚。

primes是一個無限的集合。您可以設置type參數來提高非素數的ValueError。