Python argparse: 强制使列表中的项唯一

5

使用下面的choices=servers验证列表项目是很好的.

servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer", "SkeppServer", "HavsServer", "SovServer" ]
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--only', nargs='*', choices=servers, help='Space separated list of case sensitive server names to process')

有没有可能强制列表中的某个项目是唯一的,这样就不允许重复?


3
只需要将服务器列表转换为 set,这样就可以去掉重复的部分。 - Katriel
4个回答

7
使用argparse正确处理重复项的方法是创建自己的argparse.Action类,该类负责使用set来处理,正如其他答案所建议的那样:
import argparse

class UniqueAppendAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        unique_values = set(values)
        setattr(namespace, self.dest, unique_values)

servers = ["ApaServer", "BananServer", "GulServer", "SolServer",
           "RymdServer", "SkeppServer", "HavsServer", "SovServer" ]
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--only', nargs='*', choices=servers, action=UniqueAppendAction,
                    help='Space separated list of case sensitive server names to process')
print parser.parse_args()

示例输出:

$ python test.py -o ApaServer ApaServer
Namespace(only=set(['ApaServer']))

6
args = parser.parse_args()之后,仅需简单地使用args.only = set(args.only),我看不出有任何额外的价值。这比编写自定义操作要简短得多... - user355252
1
@lunaryorn 对于单个参数,我同意这不是非常方便的。然而,当多个参数应该具有此属性时,在add_argument方法调用中设置它更一致和可读,因为关于参数的所有信息都在一个地方。 - jcollado
2
在这种情况下,您仍然可以执行for arg in ('only1', 'only2'): setattr(args, arg, set(getattr(args, arg)))。但我理解您的观点... - user355252

4

我认为你不能用argparse来强制执行这一点,但我也不认为有必要这样做。只需要在help文件中记录重复的被忽略即可。如果用户向--only传递重复参数,只需让她这样做,并在处理选项参数时忽略重复参数(例如,在处理之前将列表转换为set())。


2
如果发现重复的参数,还应考虑向stderr发出警告,表明它们将被忽略。 - Alex Reynolds

2
修改Michel的答案:
In [1]: x = [5,6,5]

In [2]: x_nodups = list(set(x))

In [3]: x_nodups
Out[3]: [5, 6]

In [4]: x_nodups_michel = dict(map(lambda i: (i,1),x)).keys()

In [5]: x_nodups_michel
Out[5]: [5, 6]

更短。

2
以下是我用于类似目的的代码摘录:
```python # 这里是一段代码摘录 ```
该代码可供参考。
def parse_args(argv):
    class SetAction(argparse.Action):
        """argparse.Action subclass to store distinct values"""
        def __call__(self, parser, namespace, values, option_string=None):
            try:
                getattr(namespace,self.dest).update( values )
            except AttributeError:
                setattr(namespace,self.dest,set(values))
    ap = argparse.ArgumentParser(
        description = __doc__,
        formatter_class = argparse.ArgumentDefaultsHelpFormatter,
        )
    ap.add_argument('--genes', '-g',
                    type = lambda v: v.split(','),
                    action = SetAction,
                    help = 'select by specified gene')

这与jcollado的回答类似,但有一些改进:可以指定多个选项,用逗号分隔,并且它们在所有选项中进行去重(通过set)。

例如:

snafu$ ./bin/ucsc-bed -g BRCA1,BRCA2,DMD,TNFA,BRCA2 -g BRCA1
Namespace(genes=set([u'BRCA1', u'BRCA2', u'DMD', u'TNFA']))

请注意,有两个-g参数。BRCA2在第一个参数中被指定了两次,但只出现了一次。BRCA1在第一个和第二个-g选项中都被指定了,但也只出现了一次。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接