将整数列表传递给Python

40

我想把两个整数列表作为Python程序的输入参数。

例如,(从命令行)

python test.py --a 1 2 3 4 5 -b 1 2  

这个列表中的整数可以从1到50,列表2是列表1的子集。
需要帮助/建议吗?argparse是合适的模块吗?在使用它时有任何问题吗?

我已经尝试过:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--a', help='Enter list 1 ')
    parser.add_argument('--b', help='Enter list 2 ')
    args = parser.parse_args()
    print (args.a)

整数列表长什么样? - ATOzTOA
你能展示一下你将要使用的命令行吗?同时,作为问题的一部分,请添加常见的注释。 - ATOzTOA
每个列表中的整数范围从1到50。列表2是列表1的子集。 - Swati
空格分隔的值是根据约定不同的参数。要么用引号括起你的列表(“1 2 3 4 5”),要么用逗号分隔它们(1,2,3,4,5)-- 然后 argparse 将把它们视为一个参数。 - Katriel
@katrielalex:nargs="+"会改变这种行为,因此它将-a 1 2 3作为一个列表处理。 - Jakub M.
6个回答

83
< p > argparse 支持 nargs 参数, 它告诉你它接受多少个参数。 当 nargs="+" 时,它将接受一个或多个参数,因此您可以传递 -b 1 2 3 4 并将其分配为列表到 b 参数中。

# args.py
import argparse

p = argparse.ArgumentParser()

# accept two lists of arguments
# like -a 1 2 3 4 -b 1 2 3
p.add_argument('-a', nargs="+", type=int)
p.add_argument('-b', nargs="+", type=int)
args = p.parse_args()

# check if input is valid
set_a = set(args.a)
set_b = set(args.b)

# check if "a" is in proper range.
if len(set_a - set(range(1, 51))) > 0: # can use also min(a)>=1 and max(a)<=50
    raise Exception("set a not in range [1,50]")

# check if "b" is in "a"
if len(set_b - set_a) > 0:
    raise Exception("set b not entirely in set a")

# you could even skip len(...) and leave just operations on sets
# ...

所以你可以运行:

$ python arg.py  -a 1 2 3 4 -b 2 20
Exception: set b not entirely in set a

$ python arg.py  -a 1 2 3 4 60 -b 2
Exception: set a not in range [1,50]

这是合法的:

$ python arg.py  -a 1 2 3 4 -b 2 3

好决定!如果需要列出50个数字而不是5个,那会很长)) - Ellochka Cannibal
因为您所要求的 就是 集合检查。当您检查 B 是否在 A 中时,它就是集合操作 - 检查集合 b - 集合 a 是否为空。对于范围,我可以使用 min(a) >= 1 and max(a) <= 50,尽管我希望保持一致性。您问的是 "List2 是 List1 的子集",对吗? - Jakub M.
为了进行有效性检查,为什么不使用 if all(1 <= a <= 50 for a in set_a) - Inbar Rose
@InbarRose:不错,如果我重构它,我会使用它。 - Jakub M.
1
在这种情况下,我该如何设置默认值列表? - aviator
@aviator,你可以将默认值设置为列表,例如 default=[0, 1, 2, 3, 4] - ofekp

15
你可以将它们作为字符串传递,然后转换为列表。 你可以使用 argparse 或 optparse。
您可以使用 argparseoptparse
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--l1', type=str)
parser.add_argument('--l2', type=str)
args = parser.parse_args()
l1_list = args.l1.split(',') # ['1','2','3','4']

例子:python prog.py --l1=1,2,3,4

另外,您可以传递一行类似于1-50的内容,然后在“-”上拆分并构建范围。像这样:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--l1', type=str, help="two numbers separated by a hyphen")
parser.add_argument('--l2', type=str)
args = parser.parse_args()
l1_list_range = xrange(*args.l1.split('-')) # xrange(1,50)
for i in l1_list_range:
    print i

示例:python prog.py --l1=1-50

我认为逻辑你自己可以写。 :)


1
有任何示例代码吗?如果任何列表为空或包含超出范围的数字,我还想抛出错误? - Swati
请携带您想要传递的示例列表。 - Ellochka Cannibal
3
StackOverflow 不是一个编写代码的服务。请您自己尝试解决问题,然后再寻求帮助来改进您的解决方案。 - Burhan Khalid
样例列表list1包含数字1-50,而list2则包含了list1中的一部分数字。 - Swati

7
这对我很有帮助: parser.add_argument('-i', '--ids', help="逗号分隔的ID列表", type=lambda x: x.split(',')) 编辑:
我刚意识到这实际上并没有回答所提出的问题。 Jakub 有正确的解决方案。

1

optparseargparse的工作方式是从命令行读取参数,参数由空格分隔,因此如果您想通过optparseargparse从命令行界面输入整数列表,则可以通过去除空格或用"括起参数来实现,例如:

> my_script.py --a "1 2 3 4 5" --b "1 2"

或者:

> my_script.py --a 1,2,3,4,5 --b  1,2

您的脚本需要将这些输入转换为实际列表。
使用 argparse 语法(与 optparse 非常相似):
# with spaces and "
a_lst = [i for i in args.a.split(' ')] 
b_lst = [i for i in args.b.split(' ')]

# without spaces and ,
a_lst = [i for i in args.a.split(',')] 
b_lst = [i for i in args.b.split(',')]

另一种方法是导入要运行的模块并将列表对象传递给处理代码的类,或者使用 while 循环和 raw_input/input 收集所需的列表。

1
如果唯一的参数是列表和分隔符,你可以相对简单地完成它:
sa = sys.argv.index('-a')
sb = sys.argv.index('-b')
lista = [int(i) for i in sys.argv[sa+1:sb]]
listb = [int(i) for i in sys.argv[sb+1:]]

添加验证很容易:

aval = [i for i in lista if i>1 and i<50]
if len(aval) < len(lista):
    print 'The -a list contains invalid numbers.'
bval = [i for i in listb if i>1 and i<50]
if len(bval) < len(listb):
    print 'The -b list contains invalid numbers.'

生成帮助信息:
if sys.argv[1] in ['-h', '-H'] or len(sys.argv) == 1:
    print "Usage: <name> -a [list of integers] -b [list of integers]"

我喜欢你的方法,我如何提供有关输入参数和任何范围验证的帮助? - Swati

1

为了完整起见,我添加了这个。我惊讶地发现没有看到这种方法。

from argparse import Action, ArgumentParser


class CommaSeparatedListAction(Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values.split(','))


parser = ArgumentParser()
parser.add_argument('-l', action=CommaSeparatedListAction)
print(parser.parse_args('-l a,b,c,d'.split()))

# Namespace(l=['a', 'b', 'c', 'd'])

这只是一个基本的例子,但您还可以添加验证或以某种方式转换值,例如强制将它们转换为大写。
from argparse import Action, ArgumentParser


class UppercaseLetterCommaSeparatedListAction(Action):
    def __call__(self, parser, namespace, values, option_string=None):
        letters = values.split(',')
        for l in letters:
            self._validate_letter(parser, l)
        setattr(
            namespace,
            self.dest,
            list(map(lambda v: v.upper(), letters))
        )

    def _validate_letter(self, parser, letter):
        if len(letter) > 1 or not letter.isalpha():
            parser.error('l must be a comma separated list of letters')


parser = ArgumentParser()
parser.add_argument('-l', action=UppercaseLetterCommaSeparatedListAction)
print(parser.parse_args('-l a,b,c,d'.split()))

# Namespace(l=['A', 'B', 'C', 'D'])

parser = ArgumentParser()
parser.add_argument('-l', action=UppercaseLetterCommaSeparatedListAction)
print(parser.parse_args('-l a,bb,c,d'.split()))

# usage: list.py [-h] [-l L]
# list.py: error: l must be a comma separated list of letters

parser = ArgumentParser()
parser.add_argument('-l', action=UppercaseLetterCommaSeparatedListAction)
print(parser.parse_args('-l a,1,c,d'.split()))

# usage: list.py [-h] [-l L]
# list.py: error: l must be a comma separated list of letters

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