Passing integer lists to python

后端 未结 6 642
感情败类
感情败类 2021-01-07 19:23

I want to pass 2 lists of integers as input to a python program.

For e.g, (from command line)

python test.py --a 1 2 3 4 5 -b 1 2  
相关标签:
6条回答
  • 2021-01-07 19:58

    This worked for me:

    parser.add_argument('-i', '--ids', help="A comma separated list IDs", type=lambda x: x.split(','))

    EDIT:

    I have just realised that this doesn't actually answer the question being asked. Jakub has the correct solution.

    0 讨论(0)
  • 2021-01-07 19:59

    You can pass them as strings than convert to lists. You can use argparse or optparse.

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

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

    Also,as a line you can pass something like this 1-50 and then split on '-' and construct range. Something like this:

    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
    

    Example: python prog.py --l1=1-50

    Logic I think you can write yourself. :)

    0 讨论(0)
  • 2021-01-07 20:00

    Just adding this one for completeness. I was surprised that I didn't see this approach.

    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'])
    

    This just a basic example, but you can also add validation or transform values in someway such as coercing them to uppercase.

    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
    
    0 讨论(0)
  • 2021-01-07 20:10

    If the only arguments are the lists and the separators, you can do it relatively simply:

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

    Adding validation is easy:

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

    Producing a help message:

    if sys.argv[1] in ['-h', '-H'] or len(sys.argv) == 1:
        print "Usage: <name> -a [list of integers] -b [list of integers]"
    
    0 讨论(0)
  • 2021-01-07 20:15

    The way that optparse and argparse work is they read arguments from the command line, arguments are split by white-space, so if you want to input your list of integers through the command line interfact from optparse or argparse - you can do this by removing the spaces, or by surrounding your argument with ", example:

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

    or:

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

    Your script then needs to convert these inputs into an actual list.

    Using argparse syntax (very similar for 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(',')]
    

    Another way to do this would be by either importing the module you want to run and passing the list objects to a class that deals with your code, or by using a while loop and raw_input/input to collect the desired list.

    0 讨论(0)
  • 2021-01-07 20:16

    argparse supports nargs parameter, which tells you how many parameters it eats. When nargs="+" it accepts one or more parameters, so you can pass -b 1 2 3 4 and it will be assigned as a list to b argument

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

    So you can run:

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

    And this is valid:

    $ python arg.py  -a 1 2 3 4 -b 2 3
    
    0 讨论(0)
提交回复
热议问题