5

我有以下代码来创建一个容器,该容器假装其行为类似于所有素数的集合(实际上隐藏了一个记忆的蛮力素数测试)

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

但它不能很好地与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

文档只是这么

任何支持 in 运算符的对象都可以作为选择值传递,因此 dict 对象、set 对象、自定义容器等都被支持。

显然我不想迭代无限的素数“集合”。那么为什么要argparse尝试map我的素数呢?它不只需要inandnot in吗?

4

3 回答 3

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内容,您可能会破解它来做正确的事情。

于 2012-12-12T05:56:15.223 回答
4

这是一个文档错误。这是issue16468 ,由PR 15566于 2019 年 8 月修复。

编写的库要求choices参数不仅是容器,而且是可迭代的,它试图列出可用的选项,这对您的情况不起作用。你可以尝试通过给它一个__iter__只返回一些信息字符串的假来破解它。

于 2012-12-12T06:00:32.727 回答
1

choices用于可以枚举所有允许值(有限(小)集)的参数。文档应该更清楚。

primes是一个无限集。您可以设置type参数以提高非素数的 ValueError 。

于 2012-12-12T06:15:07.603 回答